Как проверить, создаст ли Терраформ ресурс

#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"]
  }
}