I am trying to iterate in resource "launchdarkly_feature_flag" variables with dynamic block that might have optional nested objects - "variations" (could be 0 or 2+):
variable "feature_flags" {
  default = {
    flag_1 = {
      project_key = "project"
      key         = "number example"
      name        = "number example flag"
      description = "this is a multivariate flag with number variations."
      variation_type = "number"
      variations = {
        value = 100
      }
      variations = {
        value = 300
      }
      tags = ["example"]
    },
    flag_2 = {
      project_key = "project"
      key = "boolean example"
      name = "boolean example flag"
      description = "this is a boolean flag"
      variation_type = "boolean"
      tags = ["example2"]
    }
  }
}
Ive tried various scenarios of how to get all flag and always face different problems. Piece of code:
resource "launchdarkly_feature_flag" "ffs" {
  for_each = var.feature_flag_map
  project_key = each.value.project_key
  key  = each.value.key
  name = each.value.name
  description = each.value.description
  variation_type = each.value.variation_type
  
  # main problem here
  dynamic variations {
    for_each = lookup(each.value, "variations", {}) == {} ? {} : {
      content {
        value = each.value.variations.value
      }
    }
  }
  tags = each.value.tags
}
Could you please help with that? I am using 0.14v of Terraform
The first step would be to tell Terraform what type of value this variable expects. While it's often okay to omit an explicit type for a simple value and let Terraform infer it automatically from the default, when the data structure is this complex it's better to tell Terraform what you intended, because then you can avoid it "guessing" incorrectly and giving you confusing error messages as a result.
The following looks like a suitable type constraint for the default value you showed:
variable "feature_flags" {
  type = map(object({
    project_key    = string
    key            = string
    name           = string
    description    = string
    variation_type = string
    tags           = set(string)
    variations = list(object({
      value = string
    }))
  }))
}
With the type written out, Terraform will guarantee that any var.feature_flags value conforms to that type constraint, which means that you can then make your dynamic decisions based on whether the values are null or not:
resource "launchdarkly_feature_flag" "ffs" {
  for_each = var.feature_flags
  project_key    = each.value.project_key
  key            = each.value.key
  name           = each.value.name
  description    = each.value.description
  variation_type = each.value.variation_type
  tags           = each.value.tags
  dynamic "variations" {
    for_each = each.value.variations != null ? each.value.variations : []
    content {
      variations.value.value
    }
  }
}
As written above, Terraform will require that all values in feature_flags have all of the attributes defined, although the caller can set them to null to indicate that they are unset.
At the time of writing, in Terraform v0.14, there is an experimental feature for marking attributes as optional which seems like it would, once stabilized, be suitable for this use-case. Marking some or all of the attributes as optional would allow callers to omit them and thus cause Terraform to automatically set them to null, rather than the caller having to explicitly write out the null value themselves.
Hopefully that feature is stabilized in v0.15, at which point you could return to this and add the optional annotations to some attributes without changing anything else about the module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With