如何检查 Terraform 是不是会创建资源
Posted
技术标签:
【中文标题】如何检查 Terraform 是不是会创建资源【英文标题】:How to check, if Terraform will create resource如何检查 Terraform 是否会创建资源 【发布时间】:2021-10-30 21:31:54 【问题描述】:我在我的工作流程中使用 Terraform + AWS Lambda,并且我想在每个计划或应用操作期间使用我现有实例的 ARN 调用一些 lambda。我使用这种结构:
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"]) && !(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.
现在我正在寻找 terraform 检查资源是否存在或将被创建。我尝试向地图生成器添加参数以排除未创建的实例(在我的工作流程中可以),如下所示:
if can(local.tags_map[node]["backup"]) && !(can(aws_instance.centralized_node[node].root_block_device.0.tags["backup"])) && can(aws_instance.centralized_node[node].arn)
但它不起作用,terraform认为它可以达到未创建实例的ARN值,但稍后。
请帮我找到避免此类错误的方法。
【问题讨论】:
你想达到什么目的?看起来您正在尝试将 Terraform 用于它不打算用于的东西。为什么不在您的脚本中使用 AWS CLI 在运行 Terraform 之前调用 Lambda。保持简单。 我使用基于 ebs 卷标签的 AWS 快照备份功能。如果备份卷标签被破坏,这部分代码应该自动修复它们。此外,我无法使用 terraform 附加这些标签,因为它们包含实例和卷 ID,这就是我使用 Lambda 进行标签管理的原因。 【参考方案1】:似乎您的local.centralized_nodes
不是由而是自动生成的。如果是这样,你 can't use it 和 for_each
。
map的keys(或者一组字符串情况下的所有值)必须是已知值,否则你会得到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"]) && 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"]
【讨论】:
以上是关于如何检查 Terraform 是不是会创建资源的主要内容,如果未能解决你的问题,请参考以下文章