Reputation: 607
I am trying to set default values on my map(objects)
variable in terraform but I am getting the following error when using my module:
The given value is not suitable for child module variable "virtual_servers"
│ defined at .terraform/modules/{module_name}/variables.tf:122,1-27: element
│ "{element_name}": attributes "client_profiles", "irules", "profiles",
│ "rev_zone", "server_profiles", and "source_address_translation" are
│ required.
My understanding is that I should be able to provide sensible defaults in my module and then override those defaults when calling the module.
Here is the code:
Module
variables.tf:
variable "virtual_servers" {
type = map(object({
port = number
fwd_zone = string
rev_zone = string
source_address_translation = string
irules = list(string)
profiles = list(string)
client_profiles = list(string)
server_profiles = list(string)
}))
default = {
default = {
port = 1
fwd_zone = "test"
rev_zone = "test"
source_address_translation = "test"
irules = null
profiles = null
client_profiles = null
server_profiles = null
}
}
}
main.tf
resource "virtual_server" "this" {
for_each = var.virtual_servers
port = each.value.port
source_address_translation = each.value.source_address_translation
irules = each.value.irules
profiles = each.value.profiles
client_profiles = each.value.client_profiles
server_profiles = each.value.server_profiles
}
Making use of the module
main.tf
module "module_name" {
source = "module_source"
virtual_servers_1 = {
"name" = {
port = 80
fwd_zone = "override"
}
"virtual_servers_2" = {
port = 80
fwd_zone = "override"
}
}
}
Can anyone point me in the direction of where I am going wrong?
EDIT: If I pass in all the values required to virtual_servers_1 and virtual_servers_2 it works. However I want to be able to supply default values.
Upvotes: 3
Views: 14623
Reputation: 74694
The default
argument inside a variable
block is only for situations where the caller doesn't set the variable at all. Setting a default
tells Terraform that the overall argument should be optional and to use the given value instead if it isn't set.
There is no corresponding feature for individual attributes. If you define an attribute as part of an object type then it must always be present in the argument in order for the value to match the type, but the caller can set the attribute to null
explicitly in order to include it in the type without providing a value for it:
module "module_name" {
source = "module_source"
virtual_servers_1 = {
"name" = {
port = 80
fwd_zone = "override"
source_address_translation = null
irules = null
profiles = null
client_profiles = null
server_profiles = null
}
"virtual_servers_2" = {
port = 80
fwd_zone = "override"
source_address_translation = null
irules = null
profiles = null
client_profiles = null
server_profiles = null
}
}
}
Note that, because as noted above default
is only for when the variable isn't set at all, those null
values will appear directly in the var.virtual_servers
value. If you want to replace them with actual default values for use elsewhere in your module then you can derive a new value where those values are replaced by defaults, using the coalesce
function in a local value:
locals {
virtual_servers_1 = tomap({
for k, s in var.virtual_servers_1 : k => {
port = coalesce(s.port, 1)
fwd_zone = coalesce(s.fwd_zone, "test")
rev_zone = coalesce(s.rev_zone, "test")
source_address_translation = coalesce(s.source_address_translation, "test")
irules = coalesce(s.irules, tolist([]))
profiles = coalesce(s.profiles, tolist([]))
client_profiles = coalesce(s.client_profiles, tolist([]))
server_profiles = coalesce(s.server_profiles, tolist([]))
}
})
}
You can then use local.virtual_servers_1
instead of var.virtual_servers_1
elsewhere in the module to guarantee that you'll never encounter a null
, and will instead see the default value if the input was null
. (I set the list ones to default to an empty list because that's typically easier to work with elsewhere than a null list.)
Upvotes: 2