具有下游依赖项的 Terraform 条件“for_each”

Posted

技术标签:

【中文标题】具有下游依赖项的 Terraform 条件“for_each”【英文标题】:Terraform conditional `for_each` with downstream dependencies 【发布时间】:2021-12-13 23:07:18 【问题描述】:

给定一些条件/过滤的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"
  ,
  . . .

然后像这样构建我的 terraform:

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.

不确定是否有办法在 resourcedata 对象之间来回交换?

【问题讨论】:

【参考方案1】:

我通常建议通过艰难决定创建存储桶是否属于其范围的一部分,然后让调用模块始终声明其自己的 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)
  ))

接下来让我们为这些元素的子集声明 aws_s3_bucket 资源,这些元素设置了 create_staging_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
  # ...

【讨论】:

谢谢,我什至不知道有合并,也绝对没有意识到使用局部变量的威力。来自很多 TF12,我最终创建了两个以地图为条件的资源(resource.s3 和 data.s3)和两个通知资源,但这看起来更干净。

以上是关于具有下游依赖项的 Terraform 条件“for_each”的主要内容,如果未能解决你的问题,请参考以下文章

具有来自 .tfvars 的值的 terraform for_each 实现

具有依赖项的 Keycloak 扩展

具有其他依赖项的 ConfigurationProvider

具有依赖项的 registerModule

无法安装具有 C 依赖项的 Python 库

具有 maven 依赖项的 Java ClassNotFoundException