具有下游依赖性的 Terraform 条件 `for_each`
Terraform conditional `for_each` with downstream dependencies
给定一些 conditional/filtered for_each
语句,如何将剩余的对象用于下游依赖项?
注意:Terraform 0.13.7
例如,如果用户没有 s3 存储桶,terraform 应该创建一个并设置它的通知策略。如果他们确实有一个桶,那么 terraform 应该查找这个桶并设置它的通知。
到目前为止,我已经尝试像这样格式化我的有效负载:
"snowpipes": {
. . .
"create_staging_bucket": true,
"staging_bucket": {
"name": "existing-bucket-deployment",
"url": "old-dirty-bucket",
"arn": "arn:aws:s3:::old-dirty-bucket"
},
. . .
}
然后像这样构建我的地形:
resource "aws_s3_bucket" "staging_bucket" {
for_each = {for k, v in var.snowpipes : k => v if v.create_staging_bucket == true}
bucket = lower(each.value.staging_bucket.url)
}
resource "aws_s3_bucket_notification" "bucket_notification" {
for_each = var.snowpipes
bucket = aws_s3_bucket.staging_bucket[each.key].id
. . .
}
但后来我得到这样的错误,表明给定的密钥已被过滤掉:
Error: Invalid index
on main.tf line 504, in resource "aws_s3_bucket_notification" "bucket_notification":
504: bucket = aws_s3_bucket.staging_bucket[each.key].id
|----------------
| aws_s3_bucket.staging_bucket is object with no attributes
| each.key is "existing-bucket-deployment"
The given key does not identify an element in this collection value.
不确定是否有办法在 resource
和 data
对象之间来回交换?
我通常建议通过做出关于创建存储桶是否在其范围内的艰难决定,然后让调用模块 always 声明来保持共享模块更简单它自己的 S3 存储桶,如果您确定 S3 存储桶不在其范围内,但我也可以看到,有时以这种方式保持灵活性很方便,并且这样做可能会以一些额外的复杂性为代价配置。
让我们首先展示我将假设的变量声明:
variable "snowpipes" {
type = map(object({
create_staging_bucket = bool
staging_bucket = object({
name = string
url = string
arn = string
})
# (and whatever else you need, immaterial to this question)
}))
}
接下来让我们为设置了 create_staging_bucket
的这些元素的子集声明 aws_s3_bucket
资源,这与您已经编写的相同:
resource "aws_s3_bucket" "staging_bucket" {
for_each = {
for k, v in var.snowpipes : k => v
if v.create_staging_bucket == true
}
bucket = lower(each.value.staging_bucket.url)
}
到目前为止,我希望我基本上只是重复了您已有的内容。我的下一步是将此资源的结果合并到原始变量的设置中,以便创建所有暂存桶的平面图,无论它们是否在此处创建:
locals {
staging_buckets = merge(
{ for k, sp in var.snowpipes : k => sp.staging_bucket }
{
for k, b in aws_s3_bucket.staging_bucket : k => {
name = b.bucket
url = b.bucket # (not sure about this, but following your example above)
arn = b.arn
}
}
}
}
现在我们回到了一个映射,它具有与我们在 var.snowpipes
中开始时相同的所有键,其中一些元素只是逐字输入的内容,其他元素是基于我们声明的资源。由于 merge
的优先级行为,它会更愿意使用第二个地图中的键,而不是第一个地图中键冲突的键。
我们可以将其用于存储桶通知资源:
resource "aws_s3_bucket_notification" "bucket_notification" {
for_each = local.staging_buckets
bucket = each.value.name
# ...
}
给定一些 conditional/filtered for_each
语句,如何将剩余的对象用于下游依赖项?
注意:Terraform 0.13.7
例如,如果用户没有 s3 存储桶,terraform 应该创建一个并设置它的通知策略。如果他们确实有一个桶,那么 terraform 应该查找这个桶并设置它的通知。
到目前为止,我已经尝试像这样格式化我的有效负载:
"snowpipes": {
. . .
"create_staging_bucket": true,
"staging_bucket": {
"name": "existing-bucket-deployment",
"url": "old-dirty-bucket",
"arn": "arn:aws:s3:::old-dirty-bucket"
},
. . .
}
然后像这样构建我的地形:
resource "aws_s3_bucket" "staging_bucket" {
for_each = {for k, v in var.snowpipes : k => v if v.create_staging_bucket == true}
bucket = lower(each.value.staging_bucket.url)
}
resource "aws_s3_bucket_notification" "bucket_notification" {
for_each = var.snowpipes
bucket = aws_s3_bucket.staging_bucket[each.key].id
. . .
}
但后来我得到这样的错误,表明给定的密钥已被过滤掉:
Error: Invalid index
on main.tf line 504, in resource "aws_s3_bucket_notification" "bucket_notification":
504: bucket = aws_s3_bucket.staging_bucket[each.key].id
|----------------
| aws_s3_bucket.staging_bucket is object with no attributes
| each.key is "existing-bucket-deployment"
The given key does not identify an element in this collection value.
不确定是否有办法在 resource
和 data
对象之间来回交换?
我通常建议通过做出关于创建存储桶是否在其范围内的艰难决定,然后让调用模块 always 声明来保持共享模块更简单它自己的 S3 存储桶,如果您确定 S3 存储桶不在其范围内,但我也可以看到,有时以这种方式保持灵活性很方便,并且这样做可能会以一些额外的复杂性为代价配置。
让我们首先展示我将假设的变量声明:
variable "snowpipes" {
type = map(object({
create_staging_bucket = bool
staging_bucket = object({
name = string
url = string
arn = string
})
# (and whatever else you need, immaterial to this question)
}))
}
接下来让我们为设置了 create_staging_bucket
的这些元素的子集声明 aws_s3_bucket
资源,这与您已经编写的相同:
resource "aws_s3_bucket" "staging_bucket" {
for_each = {
for k, v in var.snowpipes : k => v
if v.create_staging_bucket == true
}
bucket = lower(each.value.staging_bucket.url)
}
到目前为止,我希望我基本上只是重复了您已有的内容。我的下一步是将此资源的结果合并到原始变量的设置中,以便创建所有暂存桶的平面图,无论它们是否在此处创建:
locals {
staging_buckets = merge(
{ for k, sp in var.snowpipes : k => sp.staging_bucket }
{
for k, b in aws_s3_bucket.staging_bucket : k => {
name = b.bucket
url = b.bucket # (not sure about this, but following your example above)
arn = b.arn
}
}
}
}
现在我们回到了一个映射,它具有与我们在 var.snowpipes
中开始时相同的所有键,其中一些元素只是逐字输入的内容,其他元素是基于我们声明的资源。由于 merge
的优先级行为,它会更愿意使用第二个地图中的键,而不是第一个地图中键冲突的键。
我们可以将其用于存储桶通知资源:
resource "aws_s3_bucket_notification" "bucket_notification" {
for_each = local.staging_buckets
bucket = each.value.name
# ...
}