You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现仅当bucket_lifecycle非空时创建多规则S3生命周期配置?

Terraform S3生命周期配置资源的条件创建问题

问题背景

需要实现:仅当生命周期规则变量非空时,创建aws_s3_bucket_lifecycle_configuration资源;变量为空时不创建该资源。当前代码在变量非空时可正常生成多规则,但变量为空时执行失败。尝试给资源添加for_each条件后,出现「Invalid value for "inputMap" parameter: lookup() requires a map as the first argument.」错误。

当前代码

locals {
  bucket_lifecycle     = { for k, v in var.lifecycle_rules : k => v }
}

resource "aws_s3_bucket_lifecycle_configuration" "this" {
  bucket = aws_s3_bucket.this.id

  dynamic "rule" {
    for_each = local.bucket_lifecycle

    content {
      id     = try(rule.value.id, null)
      status = try(rule.value.enabled, true) ? "Enabled" : "Disabled"

      dynamic "filter" {
        for_each = try(rule.value.prefix, null) == null ? [] : toset(["0"])

        content {
          prefix = lookup(rule.value, "prefix", null)

          and {
            tags = lookup(rule.value, "tags", null)
          }
        }
      }

      dynamic "expiration" {
        for_each = lookup(rule.value, "expiration", {})

        content {
          date                         = lookup(expiration.value, "date", null)
          days                         = lookup(expiration.value, "days", null)
          expired_object_delete_marker = lookup(expiration.value, "expired_object_delete_marker", false)
        }
      }

      dynamic "noncurrent_version_expiration" {
        for_each = lookup(rule.value, "noncurrent_version_expiration", {})

        content {
          noncurrent_days = lookup(noncurrent_version_expiration.value, "days", null)
        }
      }

      dynamic "noncurrent_version_transition" {
        for_each = lookup(rule.value, "noncurrent_version_transition", {})

        content {
          noncurrent_days = lookup(noncurrent_version_transition.value, "days", null)
          storage_class   = noncurrent_version_transition.value.storage_class
        }
      }

      dynamic "transition" {
        for_each = lookup(rule.value, "transition", {})

        content {
          date          = lookup(transition.value, "date", null)
          days          = lookup(transition.value, "days", null)
          storage_class = transition.value.storage_class
        }
      }
    }
  }
}

修改尝试代码

resource "aws_s3_bucket_lifecycle_configuration" "this" {
  for_each = length(local.bucket_lifecycle) > 0 ? local.bucket_lifecycle : {}

  bucket = aws_s3_bucket.this.id

  dynamic "rule" {
    for_each = each.value
...
}

模块配置

module "s3" {
[...]
  lifecycle_rules = [
    {
      id = "first"
      enable = true
      prefix = "*/path1/"
      expiration = [
        {
          days = 1
        }
      ]

      noncurrent_version_expiration = [
        {
          days = 1
        }
      ]
    },
    {
      id = "second"
      enable = true
      prefix = "*/path2/"
      expiration = [
        {
          days = 1
        }
      ]

      noncurrent_version_expiration = [
        {
          days = 1
        }
      ]
    }
  ]
  policy = ""
}

解决方案

核心问题

  1. 原代码未对资源添加条件创建逻辑,空规则时会生成无效的空生命周期配置。
  2. 修改尝试中错误地将规则map作为for_each的迭代对象——aws_s3_bucket_lifecycle_configuration是单个资源对应bucket的所有规则,for_each应控制是否创建整个资源,而非拆分规则。
  3. 部分字段迭代逻辑错误:模块中expiration等是列表类型,原代码用空map作为默认值,导致lookup报错。

修复后的完整代码

locals {
  # 空规则时生成空map,非空时转成以规则ID为键的map(避免默认索引键的潜在问题)
  bucket_lifecycle = length(var.lifecycle_rules) > 0 ? { for rule in var.lifecycle_rules : rule.id => rule } : {}
}

resource "aws_s3_bucket_lifecycle_configuration" "this" {
  # 仅当有规则时创建资源:用toset生成单元素集合,空规则时用空集合跳过创建
  for_each = length(local.bucket_lifecycle) > 0 ? toset(["lifecycle_config"]) : []
  bucket   = aws_s3_bucket.this.id

  dynamic "rule" {
    for_each = local.bucket_lifecycle

    content {
      id     = try(rule.value.id, null)
      # 匹配模块配置中的字段名:enable而非enabled
      status = try(rule.value.enable, true) ? "Enabled" : "Disabled"

      dynamic "filter" {
        for_each = try(rule.value.prefix, null) == null ? [] : toset(["0"])

        content {
          prefix = lookup(rule.value, "prefix", null)

          # 仅当tags存在时生成and块,避免空tags导致的无效配置
          dynamic "and" {
            for_each = lookup(rule.value, "tags", null) != null ? toset(["0"]) : []
            content {
              tags = rule.value.tags
            }
          }
        }
      }

      dynamic "expiration" {
        # 迭代列表类型的expiration,空时用空列表
        for_each = try(rule.value.expiration, [])

        content {
          date                         = lookup(expiration.value, "date", null)
          days                         = lookup(expiration.value, "days", null)
          expired_object_delete_marker = lookup(expiration.value, "expired_object_delete_marker", false)
        }
      }

      dynamic "noncurrent_version_expiration" {
        for_each = try(rule.value.noncurrent_version_expiration, [])

        content {
          noncurrent_days = lookup(noncurrent_version_expiration.value, "days", null)
        }
      }

      dynamic "noncurrent_version_transition" {
        for_each = try(rule.value.noncurrent_version_transition, [])

        content {
          noncurrent_days = lookup(noncurrent_version_transition.value, "days", null)
          storage_class   = noncurrent_version_transition.value.storage_class
        }
      }

      dynamic "transition" {
        for_each = try(rule.value.transition, [])

        content {
          date          = lookup(transition.value, "date", null)
          days          = lookup(transition.value, "days", null)
          storage_class = transition.value.storage_class
        }
      }
    }
  }
}

关键修复点

  • 资源条件创建:用for_each = length(local.bucket_lifecycle) > 0 ? toset(["lifecycle_config"]) : []控制是否创建整个资源,空规则时不生成该资源。
  • 字段迭代修正:将expiration等列表类型字段的迭代默认值从空map改为空列表,匹配模块配置的结构,避免lookup报错。
  • 字段名匹配:修正status字段的取值变量,从enabled改为enable,匹配模块配置中的字段名。
  • 无效块过滤:给and块添加动态判断,仅当存在tags时才生成该块,避免空tags导致的配置错误。

内容的提问来源于stack exchange,提问作者DisplayName

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:45:02