我有一个Terraform配置,需要:
相关代码如下:
Create lambda code...
data "aws_lambda_invocation" "run_lambda" {
function_name = "${aws_lambda_function.deployed_lambda.function_name}"
input = <<JSON
{}
JSON
depends_on = [aws_lambda_function.deployed_lambda]
}
resource "aws_cloudwatch_event_rule" "aws_my_cloudwatch_rule" {
for_each = {for record in jsondecode(data.aws_lambda_invocation.run_lambda.result).entities : record.entityName => record}
name = "${each.value.entityName}-event"
description = "Cloudwatch rule for ${each.value.entityName}"
schedule_expression = "cron(${each.value.cronExpression})"
}
问题是当我运行它时,我得到:
Error: Invalid for_each argument
on lambda.tf line 131, in resource "aws_cloudwatch_event_rule" "aws_my_cloudwatch_rule":
131: for_each = {for record in jsondecode(data.aws_lambda_invocation.aws_lambda_invocation.result).entities : record.entityName => record}
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需要在创建Lambda之前在计划阶段知道Lambda返回的数组的大小。
解决此类任务的最佳方法是什么?
由于它是作为CI / CD管道的一部分运行的,因此我更喜欢不包含“ -target”标志的解决方案。
答案 0 :(得分:5)
一种可能性是重新考虑 for_each 并在适当的情况下改用 count。 for_each 有一些主要限制。我遇到了类似的问题(对我来说似乎是一个主要错误,但他们说这是一个功能) 考虑我正在部署三个虚拟机,并希望将它们绑定到负载均衡器:
resource "aws_instance" "xxx-IIS-004" {
ami = var.ami["Windows Server 2019"]
instance_type = var.depoy_lowcost ? var.default_instance_type : "m5.2xlarge"
count = "3"
...
当我尝试使用 for_each 时,我得到“for_each”值取决于无法确定的资源属性...或元组错误。
失败:
resource "aws_elb_attachment" "attachments_004" {
depends_on = [ aws_instance.xxx-IIS-004 ]
elb = data.aws_elb.loadBalancer.id
for_each = aws_instance.xxx-IIS-004[*]
instance = each.value.id
}
作品*
locals {
att_004 = join("_", aws_instance.xxx-IIS-004[*].id )
}
resource "aws_elb_attachment" "attachments_004" {
depends_on = [ aws_instance.xxx-IIS-004 ]
elb = data.aws_elb.loadBalancer.id
count = length( aws_instance.xxx-IIS-004 )
instance = split("_", local.att_004)[count.index]
}
答案 1 :(得分:1)
如果您想以纯terraform的形式解决此问题,目前的解决方法是将您的部署分为多个堆栈/阶段(例如,首先使用lambda部署一个堆栈,然后使用lambda作为第二个堆栈数据源),或者您已经发现,使用-target
部分部署堆栈,然后部署整个堆栈。 (在这种情况下,请确保删除depends_on
,因为它会将数据源始终延迟到应用阶段。)
另一种选择是使用terragrunt之类的工具,如果定义了这些模块之间的所有依赖性,则可以通过按正确的顺序部署一组terraform模块来解决部分应用问题。使用terragrunt
,您可以在一次运行中部署所有内容,例如terragrunt apply-all
。不利的一面是,您仍然无法很好地预览CI的变化,以供同行查看。
我建议将其分为两个阶段,因为您实际上可能希望在应用最终更改之前先对两个阶段进行审查。否则,您最终可能会遇到一个设置,其中lambda损坏会导致您或您的团队 未被注意 的所有现有cloudwatch规则销毁。