locals { # 1. Find and decode YAML files alert_files = fileset( "${path.root}/${var.alerts_dir}", "**/*.yaml" ) decoded_files = [ for f in local.alert_files : yamldecode(file("${path.root}/${var.alerts_dir}/${f}")) ] # 2. Flatten: each YAML may define multiple groups groups_raw = flatten([ for doc in local.decoded_files : try(doc.groups, []) ]) # 3. Inject defaults (datasource, folder, interval) and sanitize models groups = [ for g in local.groups_raw : merge(g, { uid = try(g.uid, lower(replace(g.name, " ", "-"))) folder_uid = var.folder_uid interval = try(g.interval, "${var.default_interval_seconds}s") rules = [ for r in g.rules : merge(r, { data = [ for d in r.data : merge(d, { # Preserve __expr__ for expressions, otherwise inject default UID datasource_uid = ( try(d.datasourceUid, "") == "__expr__" ? "__expr__" : var.datasource_uid ) relative_time_range = try(d.relativeTimeRange, { from = 600, to = 0 }) # Sanitize model: remove keys Grafana ignores to prevent plan drift model = { for k, v in d.model : k => v if !(k == "queryType" || k == "query_type") } }) ] }) ] }) ] }