Nested `dynamic` blocks, and using a `try()` function call on the nested `dynamic` somehow

Im in a scenario where I am using nested dynamic blocks, dynamic "widget" { } and dynamic "metric" { } below.

The issue is that for each widget iterated upon in the outer dynamic block, just like title, visualization and nrql are top-level attribute of that content { } block, so is the attribute metric when visualization = "metric_line_chart" as per the documentation here

The issue is, just like I have try() calls for when or when an attribute is not present such as in these lines:

      threshold_red = try(widget.value.threshold_red, null)
      source        = try(widget.value.source, null)

I somehow need to put a try() in for the dynamic "metric" { }.

I’ve tried it in a variety of places, try() outside such as try(dynamic "metric" { ...}, null), and dynamic "metric" { try( content {...}, null) ...}, and I don’t know that I can go deeper than that since if I understand the documentation linked above correctly, both name and values are required for a metric { } such as in:

    metric {
        name = "Apdex"
        values = [ "score" ]
    }

So here is my working code so far, without the try(), so I could just use pointers on if I can do the above somehow with the below code:

resource "newrelic_dashboard" "exampledash" {
  title = "New Relic Terraform Example"

  filter {
    event_types = [
      "Transaction"
    ]
    attributes = [
      "appName",
      "name"
    ]
  }

  dynamic "widget" {
    for_each = var.widgets
    content {
      title         = widget.value.title
      visualization = widget.value.visualization
      nrql          = try(widget.value.nrql, null)

      # I need a try() call at some point here for a `metric` when it is present
      dynamic "metric" { # nested dynamic, required for when visualization = "metric_line_chart"
        for_each = widget.value.metric
        content {
          name   = widget.value.metric.value
          values = widget.value.metric.values
        }
      }

      threshold_red = try(widget.value.threshold_red, null)
      source        = try(widget.value.source, null)
    }
  }
}

Hi @aaa,

Since try is a function, you can only use it in parts of the language that accept expressions.

In the situation you’re working with here it seems like the problem you are contending with is that widget.value might not have metric defined at all, in which case you’d like to generate zero metric blocks.

If I’ve understood that requirement correctly then I think you could meet it by making the for_each expression itself use try and have a fallback, like this:

    dynamic "metric" {
      for_each = try(widget.value.metric, [])
      content {
        name   = metric.value.name
        values = metric.value.values
      }
    }

The idea here is to treat a missing metric as if it were an empty list, and thus have the dynamic block produce zero metric blocks.

1 Like

Thank you @apparentlymart , this worked!

Just a question, is there a reason we have the fallback as an empty list, [ ], as opposed to say null? Meaning, instead do:

  ...
  for_each = try(widget.value.metric, null)
  ...

It wouldn’t be legal to write for_each = null, because a null value isn’t an iterable sequence.

1 Like

Makes perfect, sense, thank you again!

Nested dynamic blocks, and using a try() function call on the nested dynamic somehow Terraform

Apr 15

1 / 5
Apr 15

1m ago

aaa

7h

Im in a scenario where I am using nested dynamic blocks, dynamic "widget" { } and dynamic "metric" { } below.

The issue is that for each widget iterated upon in the outer dynamic block, just like title, visualization and nrql are top-level attribute of that content { } block, so is the attribute metric when visualization = "metric_line_chart" as per the documentation here

The issue is, just like I have try() calls for when or when an attribute is not present such as in these lines:

      threshold_red = try(widget.value.threshold_red, null)
      source        = try(widget.value.source, null)

I somehow need to put a try() in for the dynamic "metric" { }.

I’ve tried it in a variety of places, try() outside such as try(dynamic "metric" { ...}, null), and dynamic "metric" { try( content {...}, null) ...}, and I don’t know that I can go deeper than that since if I understand the documentation linked above correctly, both name and values are required for a metric { } such as in:

    metric {
        name = "Apdex"
        values = [ "score" ]
    }

So here is my working code so far, without the try(), so I could just use pointers on if I can do the above somehow with the below code: