Open AndresFPineros opened 4 years ago
Yes please! The lack of this feature forces module developers to replicate the entire API of a provider within their code or greatly constrain users to a subset of allowed parameters.
Agreed. It would be great for code reuse, specially when dealing a large number o similar typed resources.
I can't believe you cannot pass a complex object as a var and just assign it as a single value to a block. Please tell me I'm the idiot and there is a better way to do this I just don't see it?
I'm implementing a module for a waf and there may be 1 rule or maybe 20 rules. The way the statement logic for the waf rules are constructed uses a potentially deeply nested objects/map. If I want the consumer of my module to be able to define their own rules and pass them as a map of objects map(any) then I will have to implement every possible key, and child, and child... as dynamic block. For reference : https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl.html#statement-block.
example:
variable "rules" {
type = map(any)
default = {
block-non-usa-traffic = {
name = "block-non-usa-traffic"
priority = 0
action = {
block = {
custom_response = {
response_code = 302
response_header = {
name = "Location"
value = "http://blocked.fartsmeller.com"
}
}
} }
statement = {
not_statement = {
statement = {
geo_match_statement = {
country_codes = [
"US",
]
}
}
}
}
visibility_config = {
cloudwatch_metrics_enabled = true
metric_name = "block-non-usa-traffic"
sampled_requests_enabled = true
}
},
The implementation is disgusting:
resource "aws_wafv2_web_acl" "common" {
name = local.name_prefix
scope = "REGIONAL"
default_action {
allow {}
}
dynamic "rule" {
for_each = var.rules
content {
name = "${local.name_prefix}-${rule.value.name}"
priority = rule.value.priority
# statement = rule.value["statement"] ## <--- this will not work :( so you have to do something like this: ...
dynamic "statement" {
for_each = rule.value.statement
content {
dynamic "not_statement" {
for_each = contains(keys(rule.value.statement), "not_statement' )) == true ? rule.value.statement.not_statement :[]
dynamic "geo_match_statement" {
for_each = ...
...
}
...
...
}
}
}
action {
dynamic "block" {
foreach = contains(keys(rule.value.action), "block") == true ? [1] : []
custom_response {
response_code = action.block.response_code
response_header {
name = action.block.response_header.name
value = action.block.response_header.value
}
}
}
}
When on the other hand you could just do this:
resource "aws_wafv2_web_acl" "common" {
name = local.name_prefix
scope = "REGIONAL"
default_action {
allow {}
}
dynamic "rule" {
for_each = var.rules
content {
name = "${local.name_prefix}-${rule.value.name}"
priority = rule.value.priority
statement = rule.value["statement"]
}
}
Please tell me I'm the idiot and there is a better way to do this I just don't see it?
Current Terraform Version
Use-cases
I want to be able to pass complex nested blocks as variables to avoid variable defintion overhead. Let me explain with the following code extracted from https://www.terraform.io/docs/providers/kubernetes/r/pod.html:
Here, we can see there are many nested blocks which are optional. In my use case, I have no idea which of these blocks will be used in a specific instance of the deployment. This means someone could use
node_affinity
or not, and inside that block they could userequired_during_scheduling_ignored_during_execution
orpreferred_during_scheduling_ignored_during_execution
or both, and inside those blocks other variations.It would be a "dynamic" rabbit-hole to handle all the possible scenarios in which a person can configure these nested blocks. (Really, I can't imagine how to do it without over-complicating things with the dynamic block)
It would be nice if we could (not possible right now) pass complex blocks as variables, like:
And inside the deployment use them like:
Another solution -> allow setting the content map of a dynamic block:
This way someone would configure the "node_affinity" block with any configuration they'd like without having to overthink the variable definition and type checking. I'm not sure if this contradicts the Terraform way of doing things, but it would be a nice to have. Allowing users to treat blocks like maps (or list of maps if multiple blocks are allowed) would make Terraform more dynamic and friendly.