简体   繁体   English

如何跳过在根模块中声明值(for_each 循环)

[英]How to skip declaring values in root module (for_each loop)

I am trying to build a reusable module that creates multiple S3 buckets.我正在尝试构建一个可重用的模块来创建多个 S3 存储桶。 Based on a condition, some buckets may have lifecycle rules, others do not.根据条件,一些存储桶可能具有生命周期规则,而另一些则没有。 I am using a for loop in the lifecycle rule resource and managed to do it but not on 100%.我在生命周期规则资源中使用了一个 for 循环并设法做到了,但不是 100%。


  • My var:我的变量:
variable "bucket_details" {
  type = map(object({
    bucket_name      = string
    enable_lifecycle = bool
    glacier_ir_days  = number
    glacier_days     = number
  }))
}
  • How I go through the map on the lifecycle resource:我如何通过 map 对生命周期资源进行 go:
resource "aws_s3_bucket_lifecycle_configuration" "compliant_s3_bucket_lifecycle_rule" {
  for_each = { for bucket, values in var.bucket_details : bucket => values if values.enable_lifecycle }

  depends_on = [aws_s3_bucket_versioning.compliant_s3_bucket_versioning]

  bucket = aws_s3_bucket.compliant_s3_bucket[each.key].bucket

  rule {
    id     = "basic_config"
    status = "Enabled"
    abort_incomplete_multipart_upload {
      days_after_initiation = 7
    }

    transition {
      days          = each.value["glacier_ir_days"]
      storage_class = "GLACIER_IR"
    }

    transition {
      days          = each.value["glacier_days"]
      storage_class = "GLACIER"
    }

    expiration {
      days = 2555
    }

    noncurrent_version_transition {
      noncurrent_days = each.value["glacier_ir_days"]
      storage_class   = "GLACIER_IR"
    }

    noncurrent_version_transition {
      noncurrent_days = each.value["glacier_days"]
      storage_class   = "GLACIER"
    }

    noncurrent_version_expiration {
      noncurrent_days = 2555
    }
  }
}
  • How I WOULD love to reference it in the root module:我多么想在根模块中引用它:
module "s3_buckets" {
  source = "./modules/aws-s3-compliance"

  #

  bucket_details = {
    "fisrtbucketname" = {
      bucket_name      = "onlythefisrtbuckettesting"
      enable_lifecycle = true
      glacier_ir_days  = 555
      glacier_days     = 888
    }
    "secondbuckdetname" = {
      bucket_name      = "onlythesecondbuckettesting"
      enable_lifecycle = false
    }
  }
}

So when I reference it like that, it cannot validate, because I am not setting values for both glacier_ir_days & glacier_days - understandable.因此,当我这样引用它时,它无法验证,因为我没有为glacier_ir_daysglacier_days设置值 - 可以理解。 My question is - is there a way to check if the enable_lifecycle is set to false, to not expect values for these?我的问题是 - 有没有办法检查enable_lifecycle是否设置为 false,而不是期望这些值? Currently, as a workaround, I am just setting zeroes for those and since the resource is not created if enable_lifecycle is false , it does not matter, but I would love it to be cleaner.目前,作为一种解决方法,我只是将这些设置为零,并且由于如果enable_lifecyclefalse则不会创建资源,这没关系,但我希望它更干净。

Thank you in advance.先感谢您。

The forthcoming Terraform v1.3 release will include a new feature for declaring optional attributes in an object type constraint, with the option of declaring a default value to use when the attribute isn't set.即将发布的 Terraform v1.3 版本将包括一个新功能,用于在 object 类型约束中声明可选属性,并且可以选择在未设置属性时声明要使用的默认值。

At the time I'm writing this the v1.3 release is still under development and so not available for general use, but I'm going to answer this with an example that should work with Terraform v1.3 once it's released.在我写这篇文章的时候,v1.3 版本仍在开发中,因此不能用于一般用途,但我将通过一个示例来回答这个问题,该示例一旦发布就应该与 Terraform v1.3 一起使用。 If you wish to try it in the meantime you can experiment with the most recent v1.3 alpha release which includes this feature, though of course I would not recommend using it in production until it's in a final release.如果您想同时尝试它,您可以尝试包含此功能的最新 v1.3 alpha 版本,当然我不建议在最终版本中使用它。


It seems that your glacier_ir_days and glacier_days attributes are, from a modeling perspective, attribtues that are required when the lifecycle is enabled and not required when lifecycle is disabled.从建模的角度来看,您的glacier_ir_daysglacier_days属性似乎是启用生命周期时需要的属性,而禁用生命周期时则不需要。

I would suggest modelling that by placing these attributes in a nested object called lifecycle and implementing it such that the lifecycle resource is enabled when that attribute is set, and disabled when it is left unset.我建议通过将这些属性放置在称为lifecycle的嵌套 object 中并实现它,以便在设置该属性时启用生命周期资源,并在未设置时禁用生命周期资源。

The declaration would therefore look like this:因此,声明将如下所示:

variable "s3_buckets" {
  type = map(object({
    bucket_name = string
    lifecycle = optional(object({
      glacier_ir_days = number
      glacier_days    = number
    }))
  }))
}

When an attribute is marked as optional(...) like this, Terraform will allow omitting it in the calling module block and then will quietly set the attribute to null when it performs the type conversion to make the given value match the type constraint.当一个属性像这样被标记为optional(...)时,Terraform 将允许在调用module块中省略它,然后在执行类型转换以使给定值匹配类型约束时悄悄地将属性设置为null This particular declaration doesn't have a default value, but it's also possible to pass a second argument in the optional(...) syntax which Terraform will then use instead of null as the placeholder value when the attribute isn't specified.此特定声明没有默认值,但也可以在optional(...)语法中传递第二个参数,然后 Terraform 将使用 null 代替null作为占位符值。

The calling module block would therefore look like this:因此,调用模块块看起来像这样:

module "s3_buckets" {
  source = "./modules/aws-s3-compliance"

  #

  bucket_details = {
    "fisrtbucketname" = {
      bucket_name = "onlythefisrtbuckettesting"
      lifecycle = {
        glacier_ir_days  = 555
        glacier_days     = 888
      }
    }
    "secondbuckdetname" = {
      bucket_name = "onlythesecondbuckettesting"
    }
  }
}

Your resource block inside the module will remain similar to what you showed, but the if clause of the for expression will test if the lifecycle object is non-null instead:模块内的资源块将与您显示的内容相似,但for表达式的if子句将测试lifecycle object 是否为非空:

resource "aws_s3_bucket_lifecycle_configuration" "compliant_s3_bucket_lifecycle_rule" {
  for_each = {
    for bucket, values in var.bucket_details : bucket => values
    if values.lifecycle != null
  }

  # ...
}

Finally, the references to the attributes would be slightly different to traverse through the lifecycle object:最后,对属性的引用在遍历lifecycle object 时会略有不同:

    transition {
      days          = each.value.lifecycle.glacier_days
      storage_class = "GLACIER"
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM