10

I am trying to build in Terraform a Web ACL resource https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl

This resource has the nested blocks rule->action->block and rule-> action->count

I would like to have a variable which's type allows me to set the action to either count {} or block{} so that the two following configurations are possible:

With block:

resource "aws_wafv2_web_acl" "example" {
  ...

  rule {
   ...

    action {
      block {}
    }

   ...
}

With count:

resource "aws_wafv2_web_acl" "example" {
  ...

  rule {
   ...

    action {
      count {}
    }

   ...
}

I can achieve this result with a boolean variable and dynamic blocks in a very non-declarative way so far.

My question is, can the type of a variable reference the type of a nested block, so that the content of the nested block can be passed in a variable?

What I am trying to achieve is something that would look similar to this (non working syntax):

resource "aws_wafv2_web_acl" "example" {
  ...

  rule {
   ...

    action = var.action_block

   ...
  } 
}
variable "action_block" {
  description = "Action of the rule"
  type         = <whatever type is accepted by aws_wafv2_web_acl->rule->action>
}

so that it can be passed down in a similar manner to this

module "my_waf" {
  source                   = "../modules/waf"
  action_block {
    block {}
  }
}

For reference, what I am trying to avoid:

    dynamic "action" {
      for_each = var.block  ? [] : [1]
      content {
        count {}
      }
    }

    dynamic "action" {
      for_each = var.block ? [1] : []
      content {
        block {}
      }
    }

Thank you so much for your help!

Patricio Marrone
  • 1,287
  • 15
  • 20
  • Researching more, so far it seems like it is not an option: `There are no plans to support treating a nested block type as if it were an argument, if that’s what you mean.` https://discuss.hashicorp.com/t/use-block-variables/5527/3 – Patricio Marrone Dec 16 '21 at 17:55
  • It kind of sounds like you are asking if the Terraform DSL supports generics, in which case the answer is: no. They were just introduced in Go in the recent 1.18, so it would probably be some time before they could appear in a derived DSL. – Matthew Schuchard Dec 16 '21 at 20:15
  • What's available in the Terraform language has no particular relationship to what's available in the Go language. Terraform itself and its language parser are written in Go, but the Terraform language is not derived from the Go language. – Martin Atkins Dec 17 '21 at 00:59

1 Answers1

8

The only marginal improvement I can imagine is to move the dynamic blocks one level deeper, to perhaps make it clear to a reader that the action block will always be present and it's the count or block blocks inside that have dynamic behavior:

  action {
    dynamic "count" {
      for_each = var.block ? [] : [1]
      content {}
    }
    dynamic "block" {
      for_each = var.block ? [1] : []
      content {}
    }
  }

There are some other ways you could formulate those two for_each expressions so that the input could have a different shape, but you'll need to write out a suitable type constraint for that variable yourself which matches whatever conditions you want to apply to it.

Denis V
  • 78
  • 5
Martin Atkins
  • 62,420
  • 8
  • 120
  • 138
  • Thanks for the feedback. As far as I could dig in, there's not much else that can be done. The question was mainly if you could send a block as an attribute that comes from a variable. Seems like the dynamic block with the for_each is the only alternative to try to accomplish this. – Patricio Marrone Dec 17 '21 at 14:48