I want to create a module for define override settings for this cloudflare ressource https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/zone_settings_override
variable "settings" {
type = map(string)
default = {}
}
So I thought about not defining every possible variable, instead just using a map of strings to just put that in the settings block what I want. Sure, I cannot test if its a allowed variable but i'm fine with it. So I thought I cloud do something like the following pseudo code, but something is missing and I dont know what
resource "cloudflare_zone_settings_override" "this" {
zone_id = cloudflare_zone.this.id
for each = var.settings
settings {
each.key = each.value
}
}
This provider has defined settings
as a nested block, which means that its schema is rigid and cannot be populated dynamically.
You will therefore need to explicitly assign each nested argument that you want to support in your module. There is no way to assign dynamically based on the keys in your map, because the provider expects to be able to validate the arguments statically.
Because you'll need to specify the specific arguments you want to support anyway, it'll be easier (and also more consistent with the provider's design) to declare your variable as being an object type with optional attributes, rather than a map:
variable "settings" {
type = object({
brotli = optional(string)
challenge_ttl = optional(number)
minify = optional(object({
css = string
html = string
js = string
}))
# ...etc...
})
default = {}
}
The advantage of declaring this as an object type rather than as a map is that you can then assume that all of the declared attributes will always be present in the object, although the optional ones might be null
. You can then assign them directly because null
in a resource argument is always equivalent to omitting the argument entirely.
resource "cloudflare_zone_settings_override" "this" {
zone_id = cloudflare_zone.this.id
settings {
brotli = var.settings.brotli
challenge_ttl = var.settings.challenge_ttl
dynamic "minify" {
for_each = var.settings.minify[*]
content {
css = minify.value.css
html = minify.value.html
js = minify.value.js
}
}
# ...etc...
}
}
If you are writing a shared module (that is: one intended to be called from another module using a module
block) then another option you could consider is to design your module to just export cloudflare_zone.this.id
as an output value and let the calling module define its own resource "cloudflare_zone_settings_override"
block; if you would just be passing the values from the caller verbatim into this resource anyway then you haven't really created any abstraction and so defining the resource directly in the caller would be equivalent and considerably simpler.