Taking into account this code:
locals {
pol_grp = {
a = { pol1 = "arn:aws:iam::aws:policy/IAMReadOnlyAccess",
pol2 = "arn:aws:iam::aws:policy/AmazonRoute53ReadOnlyAccess" }
b = { pol1 = "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess" }
}
pol_arns_list= toset(flatten([
for group in local.pol_grp : [
for arn in group:
arn ] ]))
pols = tomap({
for gk, group in local.pol_grp : gk => tomap({
for pk, arn in group : pk => {
arn = arn } }) })
}
output "pol_grp" { value = local.pol_grp }
output "pol_arns_list" { value = local.pol_arns_list }
output "pols" { value = local.pols }
This works and will output this:
...
pols = tomap({
"a" = tomap({
"pol1" = {
"arn" = "arn:aws:iam::aws:policy/IAMReadOnlyAccess"
}
"pol2" = {
"arn" = "arn:aws:iam::aws:policy/AmazonRoute53ReadOnlyAccess"
}
})
"b" = tomap({
"pol1" = {
"arn" = "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"
}
})
})
Leaving the object “b” empty, terraform returns error
...
pol_grp = {
a = { pol1 = "arn:aws:iam::aws:policy/IAMReadOnlyAccess",
pol2 = "arn:aws:iam::aws:policy/AmazonRoute53ReadOnlyAccess" }
b = {}
}
│ Error: Invalid function argument
│ 135: pols = tomap({
│ 136: for gk, group in local.pol_grp : gk => tomap({
│ 137: for pk, arn in group : pk => {
│ 138: arn = arn
│ 139: }
│ 140: })
│ 141: })
│ ├────────────────
│ │ local.pol_grp is object with 2 attributes
│ Invalid value for "v" parameter: cannot convert object to map of any single
│ type.
I suppose because tomap of an empty object
. I know that removing empty “b” object completely will avoid this error but for a matter of interest to know how terrafom work on this case I tried to limit the for loop
to discard empty objects before tomap using length function
without success:
...
pols = tomap({
for gk, group in local.pol_grp : gk => tomap({
for pk, arn in group : pk => {
arn = arn
}
})
if length(gk) > 0
})
...
I’m doing probably wrong assumptions and so:
- What it means
value for "v" parameter
- What it menas
cannot convert object to map of any single type
- Am I doing wrong assumption on if condition param data type ? (not an object but a string) or something like that. How can I avoid error making more robust pols definition instead of imposing not empty objects ?
Hi @Roxyrob,
Can you verify that you are using the latest terraform release? The given code does convert the map type successfully.
Ah, I see the failure now.
What you are running into here is a limitation of Terraform’s ability to convert types implicitly, or maybe just a limitation of the tomap
function itself. The v
here is the tomap
argument, and it’s failing to find a usable type for the map, probably because of the nesting.
The conversion is possible here, so I’m not sure offhand where the failure is happening, but a map(map(map(string)))
is a single map type which satisfies the data given. You would get the desired output by routing the value through a module variable with the exact type defined, for example:
variable "mapify" {
type = map(map(map(string)))
}
output "mapified" {
value = var.mapify
}
This may be a fixable bug in the tomap
function, however that is only going to be able to go so far. There are a number of difficult to resolve type inference cases already, and it will probably require a new method for type specification or in-line conversion to fully resolve.
Hi @jbardin,
probably I’m missing something here because I’m not sure about error interpetation as type conversion issue as this pol_grp
definition works:
pol_grp = {
a = { pol1 = "arn:aws:iam::aws:policy/IAMReadOnlyAccess",
pol2 = "arn:aws:iam::aws:policy/AmazonRoute53ReadOnlyAccess" }
b = { pol1 = "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess" }
}
while this does not:
pol_grp = {
a = { pol1 = "arn:aws:iam::aws:policy/IAMReadOnlyAccess",
pol2 = "arn:aws:iam::aws:policy/AmazonRoute53ReadOnlyAccess" }
b = {}
}
and the data structure is the same, with only the second code sample with an empty object (b={}).
For that very reason I thought the problem was related to presence of the empty object and I focused on the empty object exclusion attempt from the for loops
(using if length(gk) > 0).
If I’m missing something and your are right, how and what I can cast to avoid the error in this sample (code inside locals section with no declared/defined variables
).
I initially tried if condition on value (group)
instead of key (gk)
, so not sure why in the first try the if on group
didn’t work and I give a try on key (gk)…
Now I found that that solution works well using `if condition with length function on object value :
...
pols = tomap({
for gk, group in local.pol_grp : gk => tomap({
for pk, arn in group : pk => {
arn = arn
}
})
if length(group) > 0
})
...
as expected the if condition
exclude empty objects so tomap return expected output:
...
pol_grp = {
"a" = {
"pol1" = "arn:aws:iam::aws:policy/IAMReadOnlyAccess"
"pol2" = "arn:aws:iam::aws:policy/AmazonRoute53ReadOnlyAccess"
}
"b" = {}
}
pols = tomap({
"a" = tomap({
"pol1" = {
"arn" = "arn:aws:iam::aws:policy/IAMReadOnlyAccess"
}
"pol2" = {
"arn" = "arn:aws:iam::aws:policy/AmazonRoute53ReadOnlyAccess"
}
})
})