#amazon-web-services #aws-lambda #terraform #hcl
Вопрос:
Я использую Terraform AWS Lambda в своем рабочем процессе, и я хочу вызывать некоторые лямбда-коды с ARN моих существующих экземпляров во время каждого действия по планированию или применению. Я использую эту структуру:
locals {
...
centralized_nodes = {...}
tags_map = {...}
backup_map = {
for node in keys(local.centralized_nodes):
node => aws_instance.centralized_node[node].arn
if can(local.tags_map[node]["backup"]) amp;amp; !(can(aws_instance.centralized_node[node].root_block_device.0.tags["backup"]))
}
...
}
resource "aws_instance" "centralized_node" {
...
for_each = local.centralized_nodes
...
}
data "aws_lambda_invocation" "lambda_backup" {
for_each = local.backup_map
function_name = "lambdafunc"
input = jsonencode({
"resources" = [each.value]
})
}
это работало нормально, пока я не попытался добавить объект описания узла на centralized_nodes
карту и создать новый экземпляр. Когда я добавляю это, terraform показывает мне ошибку во время планирования:
Error: Invalid for_each argument
│
│ on resources.tf line 223, in data "aws_lambda_invocation" "lambda_backup":
│ 223: for_each = local.backup_map
│ ├────────────────
│ │ local.backup_map will be known only after apply
│
│ The "for_each" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work around this, use the
│ -target argument to first apply only the resources that the for_each depends on.
Теперь я ищу терраформу, чтобы проверить, существует ли ресурс или будет создан. я попытался добавить аргументы в генератор карт, чтобы исключить несозданные экземпляры (в моем рабочем процессе это нормально), как это:
if can(local.tags_map[node]["backup"]) amp;amp; !(can(aws_instance.centralized_node[node].root_block_device.0.tags["backup"])) amp;amp; can(aws_instance.centralized_node[node].arn)
Но это не работает, terraform считает, что он может достичь значения ARN для несотворенного экземпляра, но позже.
Пожалуйста, помогите мне найти способ избежать такой ошибки.
Комментарии:
1. Чего вы пытаетесь достичь? Это очень похоже на то, что вы пытаетесь использовать Терраформу для чего-то, для чего она не предназначалась. Почему бы не использовать интерфейс командной строки AWS в ваших сценариях для вызова лямбд перед запуском вашей терраформы. Пусть все будет просто.
2. Я использую функции резервного копирования моментальных снимков AWS на основе тегов томов ebs. Эта часть кода должна автоматически восстанавливать теги томов резервного копирования, если они были повреждены. Также я не могу прикрепить эти теги с помощью terraform, потому что они содержат идентификаторы экземпляров и томов, поэтому я использую Лямбды для управления тегами.
Ответ №1:
Похоже, что ваш local.centralized_nodes
не определен заранее, а сгенерирован автоматически. Если это так, вы не можете использовать его с for_each
.
Ключи карты (или все значения в случае набора строк) должны быть известными значениями, иначе вы получите сообщение об ошибке, что for_each имеет зависимости, которые не могут быть определены до применения, и может потребоваться-target.
Вы можете попробовать преобразовать свой код для использования count
, так как count
у него нет такого ограничения. Но тогда у count
вас есть свои проблемы, которые в любом случае могут помешать вам достичь ваших целей.
Ответ №2:
Я нашел единственный способ проверить, существуют ли уже такие ресурсы, как экземпляры и тома. Он использует источники данных aws_instance и aws_instances. Это мое решение:
locals {
...
centralized_nodes = {...}
tags_map = {...}
instance_name_root_volume_tags_map = {
for name, value in {for id, value in data.aws_instance.instance_id_arn_map : value.tags["Name"] => value}:
name => data.aws_ebs_volume.volume_instance_id_map[value.id].tags
}
backup_map = {
for name, value in {for id, value in data.aws_instance.instance_id_arn_map : value.tags["Name"] => value}:
name => value.arn
if !can(local.instance_name_root_volume_tags_map[name]["backup"]) amp;amp; can({for node, value in local.tags_map: value["Name"] => value}[name]["backup"]) )
}
...
}
resource "aws_instance" "centralized_node" {
...
for_each = local.centralized_nodes
...
}
data "aws_lambda_invocation" "lambda_backup" {
for_each = local.backup_map
function_name = "lambdafunc"
input = jsonencode({
"resources" = [each.value]
})
}
data "aws_instances" "existant_instances_array" {
filter {
name = "tag:Name"
values = [for tagmap in local.hiera_tags_map : tagmap["Name"]]
}
}
data "aws_instance" "instance_id_arn_map" {
for_each = toset(data.aws_instances.existant_instances_array.ids)
instance_id = each.value
}
data "aws_ebs_volume" "volume_instance_id_map" {
for_each = data.aws_instance.instance_id_arn_map
filter {
name = "attachment.instance-id"
values = [each.value.id]
}
filter {
name = "attachment.device"
values = ["/dev/sda1"]
}
}