I have a YAML file structured as follows:
alerts:
la:
la1:
description: "la1"
severity: 1
resource_counter: "004"
enabled: true
ma:
ma1:
description: "ma1"
severity: 2
enabled: true
resource_counter: "002"
ma2:
description: "ma2"
severity: 2
enabled: true
resource_counter: "003"
This YAML file is being parsed correctly in Terraform using the following locals block:
locals {
all_alerts = try(coalesce(yamldecode(file("${path.root}/alerts.yaml"))["alerts"], {}), {})
metric_alerts = try(local.all_alerts["ma"], {})
log_alerts = try(local.all_alerts["la"], {})
}
However, when I update the YAML file by adding a new key (scopes) under the alerts block like this:
alerts:
la:
la1:
description: "la1"
severity: 1
resource_counter: "004"
enabled: true
ma:
ma1:
description: "ma1"
severity: 2
enabled: true
resource_counter: "002"
ma2:
description: "ma2"
severity: 2
enabled: true
resource_counter: "003"
scopes:
- "test"
Terraform stops producing any output from the locals. All the decoded values (all_alerts, metric_alerts, and log_alerts) are now empty:
+ all_alerts_debug = {}
+ log_alerts_debug = {}
+ metric_alerts_debug = {}
It seems that the addition of the scopes key under alerts is causing the structure to break or be interpreted differently by Terraform
Also , when i remove the 'la' section then also it will work
alerts:
ma:
ma1:
description: "ma1"
severity: 2
enabled: true
resource_counter: "002"
ma2:
description: "ma2"
severity: 2
enabled: true
resource_counter: "003"
scopes:
- "test"
Same behaviour when executed against local terrafrom as well as terrafrom workspace
I managed to reproduce it with OpenTofu 1.9.0. The reason that this didn't work was because the second argument in the coalesce
function is a map. The type of output produced by yamldecode
is object
(of objects):
> type(local.all_alerts)
object({
la: object({
la1: object({
description: string,
enabled: bool,
resource_counter: string,
severity: number,
}),
}),
ma: object({
ma1: object({
description: string,
enabled: bool,
resource_counter: string,
severity: number,
}),
ma2: object({
description: string,
enabled: bool,
resource_counter: string,
scopes: tuple([
string,
]),
severity: number,
}),
}),
})
Using only coalesce(yamldecode(file("${path.root}/test.yml"))\["alerts"\], {})
(i.e, without try
) throws the following error:
Error: Error in function call
on locals.tf line 164, in locals: 164: all_alerts = coalesce(yamldecode(file("${path.root}/test.yml"))["alerts"], {})
while calling coalesce(vals...)
path.root is "."
Call to function "coalesce" failed: all arguments must have the same type.
Since the call to the coalesce
function fails, the try
block then outputs the empty map ({}
). Using nested built-in functions kind of obfuscates the real error in this case, so I would probably stick to using only yamldecode
and then implement try
logic elsewhere if required.