updated grafana modules
This commit is contained in:
parent
ae79eda745
commit
7413af8b2b
15 changed files with 159 additions and 81 deletions
|
|
@ -20,9 +20,9 @@ module "datasource" {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Alert Receiver / Contact Point
|
# Alert Receiver / Contact Point
|
||||||
module "gchat-contact-point" {
|
module "google-chat-contact-point" {
|
||||||
source = "git::https://commerce-platform.git.onstackit.cloud/commerce-platform-public/terraform-modules//grafana/contact-point-gchat?ref=main"
|
source = "git::https://commerce-platform.git.onstackit.cloud/commerce-platform-public/terraform-modules//grafana/contact-point-gchat?ref=main"
|
||||||
gchat-url = var.google_chat_url
|
google-chat-url = var.google_chat_url
|
||||||
contact-point-name = "gchat"
|
contact-point-name = "gchat"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,11 +45,11 @@ module "message-templates" {
|
||||||
module "notification-policy" {
|
module "notification-policy" {
|
||||||
source = "git::https://commerce-platform.git.onstackit.cloud/commerce-platform-public/terraform-modules//grafana/notification-policy?ref=main"
|
source = "git::https://commerce-platform.git.onstackit.cloud/commerce-platform-public/terraform-modules//grafana/notification-policy?ref=main"
|
||||||
|
|
||||||
default_contact_point_uid = module.gchat-contact-point.contact_name
|
default_contact_point_uid = module.google-chat-contact-point.contact_name
|
||||||
group_by = ["alertname"]
|
group_by = ["alertname"]
|
||||||
|
|
||||||
folder_policies = {
|
folder_policies = {
|
||||||
"Alerts" = module.gchat-contact-point.contact_name
|
"Alerts" = module.google-chat-contact-point.contact_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,7 +59,7 @@ module "alerting" {
|
||||||
|
|
||||||
alerts_dir = "alerts"
|
alerts_dir = "alerts"
|
||||||
default_datasource_uid = module.datasource.datasource_uid
|
default_datasource_uid = module.datasource.datasource_uid
|
||||||
default_receiver = module.gchat-contact-point.contact_name
|
default_receiver = module.google-chat-contact-point.contact_name
|
||||||
default_folder_uid = module.alert-folder.folder_uid
|
default_folder_uid = module.alert-folder.folder_uid
|
||||||
default_interval_seconds = 60
|
default_interval_seconds = 60
|
||||||
disable_provenance = true
|
disable_provenance = true
|
||||||
|
|
|
||||||
1
grafana/Untitled111.md
Normal file
1
grafana/Untitled111.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
locals {
|
locals {
|
||||||
#################################################################
|
# 1. Find and decode YAML files
|
||||||
# 1. Discover & decode alert YAML files from <root>/<alerts_dir>
|
|
||||||
#################################################################
|
|
||||||
alert_files = fileset(
|
alert_files = fileset(
|
||||||
"${path.root}/${var.alerts_dir}",
|
"${path.root}/${var.alerts_dir}",
|
||||||
var.file_pattern
|
"**/*.yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
decoded_files = [
|
decoded_files = [
|
||||||
|
|
@ -12,31 +10,36 @@ locals {
|
||||||
yamldecode(file("${path.root}/${var.alerts_dir}/${f}"))
|
yamldecode(file("${path.root}/${var.alerts_dir}/${f}"))
|
||||||
]
|
]
|
||||||
|
|
||||||
#################################################################
|
# 2. Flatten: each YAML may define multiple groups
|
||||||
# 2. Flatten: each file may contain multiple groups
|
|
||||||
#################################################################
|
|
||||||
groups_raw = flatten([
|
groups_raw = flatten([
|
||||||
for doc in local.decoded_files : try(doc.groups, [])
|
for doc in local.decoded_files : try(doc.groups, [])
|
||||||
])
|
])
|
||||||
|
|
||||||
#################################################################
|
# 3. Inject defaults (datasource, folder, interval) and sanitize models
|
||||||
# 3. Merge defaults & convert camelCase → snake_case
|
|
||||||
#################################################################
|
|
||||||
groups = [
|
groups = [
|
||||||
for g in local.groups_raw : merge(g, {
|
for g in local.groups_raw : merge(g, {
|
||||||
uid = try(
|
uid = try(g.uid, lower(replace(g.name, " ", "-")))
|
||||||
g.uid,
|
folder_uid = var.folder_uid
|
||||||
trim(replace(replace(lower(g.name), " ", "-"), "_", "-"), "-")
|
interval = try(g.interval, "${var.default_interval_seconds}s")
|
||||||
)
|
|
||||||
folder_uid = try(try(g.folder_uid, g.folder), var.default_folder_uid)
|
|
||||||
interval = try(g.interval, "1m")
|
|
||||||
|
|
||||||
rules = [
|
rules = [
|
||||||
for r in g.rules : merge(r, {
|
for r in g.rules : merge(r, {
|
||||||
data = [
|
data = [
|
||||||
for d in r.data : merge(d, {
|
for d in r.data : merge(d, {
|
||||||
datasource_uid = try(d.datasourceUid, var.default_datasource_uid)
|
# 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 })
|
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")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
resource "grafana_rule_group" "this" {
|
resource "grafana_rule_group" "this" {
|
||||||
for_each = {
|
for_each = { for g in local.groups : g.uid => g }
|
||||||
for g in local.groups :
|
|
||||||
g.uid => g
|
|
||||||
}
|
|
||||||
|
|
||||||
name = each.value.name
|
name = each.value.name
|
||||||
folder_uid = each.value.folder_uid
|
folder_uid = each.value.folder_uid
|
||||||
|
|
@ -21,14 +18,15 @@ resource "grafana_rule_group" "this" {
|
||||||
uid = rule.value.uid
|
uid = rule.value.uid
|
||||||
name = try(rule.value.title, rule.value.name)
|
name = try(rule.value.title, rule.value.name)
|
||||||
condition = rule.value.condition
|
condition = rule.value.condition
|
||||||
|
for = try(rule.value.for, null)
|
||||||
|
|
||||||
no_data_state = rule.value.noDataState
|
no_data_state = rule.value.noDataState
|
||||||
exec_err_state = rule.value.execErrState
|
exec_err_state = rule.value.execErrState
|
||||||
is_paused = try(rule.value.isPaused, false)
|
is_paused = try(rule.value.isPaused, false)
|
||||||
for = try(rule.value.for, null)
|
|
||||||
|
|
||||||
labels = try(rule.value.labels, {})
|
# Merge team labels with platform-injected receiver
|
||||||
annotations = try(rule.value.annotations, {})
|
annotations = try(rule.value.annotations, {})
|
||||||
|
labels = try(rule.value.labels, {})
|
||||||
|
|
||||||
dynamic "data" {
|
dynamic "data" {
|
||||||
for_each = rule.value.data
|
for_each = rule.value.data
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,10 @@ output "rule_group_ids" {
|
||||||
description = "Map: <folder_uid>.<name> → Grafana rule-group ID"
|
description = "Map: <folder_uid>.<name> → Grafana rule-group ID"
|
||||||
value = { for k, v in grafana_rule_group.this : k => v.id }
|
value = { for k, v in grafana_rule_group.this : k => v.id }
|
||||||
}
|
}
|
||||||
|
output "debug_alert_files" {
|
||||||
|
value = local.alert_files
|
||||||
|
}
|
||||||
|
output "debug_groups" {
|
||||||
|
description = "Parsed groups from YAML"
|
||||||
|
value = local.groups
|
||||||
|
}
|
||||||
|
|
@ -4,35 +4,29 @@ variable "alerts_dir" {
|
||||||
description = "Relative path to the directory containing alert rule YAML files."
|
description = "Relative path to the directory containing alert rule YAML files."
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "file_pattern" {
|
variable "datasource_uid" {
|
||||||
|
description = "Grafana datasource UID to apply to all alerts in this module"
|
||||||
type = string
|
type = string
|
||||||
default = "*.y{a,}ml"
|
|
||||||
description = "Glob pattern to match alert rule YAML files (e.g. *.yaml, *.yml)."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "default_datasource_uid" {
|
variable "folder_uid" {
|
||||||
|
description = "Grafana folder UID where alerts will be placed"
|
||||||
type = string
|
type = string
|
||||||
description = "UID of the Prometheus or Thanos datasource to use if not specified in the alert rule."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "default_receiver" {
|
variable "receiver" {
|
||||||
|
description = "Contact point name to associate with alerts"
|
||||||
type = string
|
type = string
|
||||||
description = "Name of the contact point (receiver) to use for notifications if not defined in alert rule."
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "default_folder_uid" {
|
|
||||||
type = string
|
|
||||||
description = "UID of the Grafana folder to use for alert rules when not defined in the YAML."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "default_interval_seconds" {
|
variable "default_interval_seconds" {
|
||||||
|
description = "Default evaluation interval (in seconds)"
|
||||||
type = number
|
type = number
|
||||||
default = 60
|
default = 60
|
||||||
description = "Default evaluation interval (in seconds) for alert rule groups if not set in YAML."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "disable_provenance" {
|
variable "disable_provenance" {
|
||||||
|
description = "Disable provenance flag for imported alerts"
|
||||||
type = bool
|
type = bool
|
||||||
default = false
|
default = false
|
||||||
description = "If true, disables Grafana alert provisioning provenance (sets disable_provenance = true)."
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
resource "grafana_contact_point" "this" {
|
resource "grafana_contact_point" "this" {
|
||||||
name = var.contact-point-name
|
name = var.contact_point_name
|
||||||
|
|
||||||
googlechat {
|
googlechat {
|
||||||
url = var.gchat-url
|
url = var.gchat_url
|
||||||
message = "{{ template \"gchat-body-template\" . }}"
|
message = "{{ template \"${var.template_prefix}gchat-body-template\" . }}"
|
||||||
title = "{{ template \"gchat-title-template\" . }}"
|
title = "{{ template \"${var.template_prefix}gchat-title-template\" . }}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,14 @@
|
||||||
output "contact_name" {
|
output "contact_point_name" {
|
||||||
value = grafana_contact_point.this.name
|
value = grafana_contact_point.this.name
|
||||||
description = "UID of the created contact point"
|
description = "Name of the created contact point"
|
||||||
}
|
}
|
||||||
output "contact_id" {
|
|
||||||
|
output "contact_point_id" {
|
||||||
value = grafana_contact_point.this.id
|
value = grafana_contact_point.this.id
|
||||||
description = "UID of the created contact point"
|
description = "ID of the created contact point"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "template_names" {
|
||||||
|
value = [for t in grafana_message_template.templates : t.name]
|
||||||
|
description = "List of message template names created by this module"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
grafana/contact-point-gchat/templates.tf
Normal file
24
grafana/contact-point-gchat/templates.tf
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
locals {
|
||||||
|
# Collect template files relative to root
|
||||||
|
template_files = fileset(
|
||||||
|
"${path.root}/${var.templates_dir}",
|
||||||
|
var.file_pattern
|
||||||
|
)
|
||||||
|
|
||||||
|
# Map filename (without extension) to template content
|
||||||
|
templates = {
|
||||||
|
for rel_path in local.template_files :
|
||||||
|
trimsuffix(basename(rel_path), ".tmpl") => {
|
||||||
|
content = file("${path.root}/${var.templates_dir}/${rel_path}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "grafana_message_template" "templates" {
|
||||||
|
for_each = local.templates
|
||||||
|
|
||||||
|
name = "${var.template_prefix}${each.key}"
|
||||||
|
template = each.value.content
|
||||||
|
disable_provenance = var.disable_provenance
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,11 +1,32 @@
|
||||||
# Grafana contact point
|
variable "contact_point_name" {
|
||||||
variable "gchat-url" {
|
description = "Name of the Grafana contact point"
|
||||||
description = "gchat-webhook url"
|
type = string
|
||||||
type = string
|
|
||||||
sensitive = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "contact-point-name" {
|
variable "gchat_url" {
|
||||||
description = "gchat-contact-point-name"
|
description = "Google Chat webhook URL"
|
||||||
type = string
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "templates_dir" {
|
||||||
|
description = "Path to directory containing template files (.tmpl)"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "file_pattern" {
|
||||||
|
description = "Pattern to match template files"
|
||||||
|
type = string
|
||||||
|
default = "*.tmpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "disable_provenance" {
|
||||||
|
description = "Disable provenance for message templates"
|
||||||
|
type = bool
|
||||||
|
default = false
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "template_prefix" {
|
||||||
|
description = "Optional prefix for template names to avoid collisions"
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
resource "grafana_data_source" "this" {
|
resource "grafana_data_source" "this" {
|
||||||
type = "prometheus"
|
for_each = var.datasources
|
||||||
name = var.datasource_name
|
|
||||||
url = var.datasource_url
|
name = each.key
|
||||||
|
type = each.value.type
|
||||||
|
url = var.datasource_urls[each.value.url_key]
|
||||||
|
is_default = coalesce(each.value.is_default, false)
|
||||||
|
|
||||||
basic_auth_enabled = true
|
basic_auth_enabled = true
|
||||||
basic_auth_username = var.datasource_username
|
basic_auth_username = var.datasource_users[each.value.user_key]
|
||||||
|
|
||||||
secure_json_data_encoded = jsonencode({
|
secure_json_data_encoded = jsonencode({
|
||||||
basicAuthPassword = var.datasource_password
|
basicAuthPassword = var.datasource_passwords[each.value.pass_key]
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
json_data_encoded = each.value.json_data != null ? jsonencode(each.value.json_data) : null
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
output "datasource_uid" {
|
output "datasource_uids" {
|
||||||
value = grafana_data_source.this.uid
|
description = "UIDs of created Grafana datasources"
|
||||||
|
value = { for k, v in grafana_data_source.this : k => v.uid }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,35 @@
|
||||||
# Grafana contact point
|
# Define datasources (non-sensitive metadata only)
|
||||||
variable "datasource_url" {
|
variable "datasources" {
|
||||||
type = string
|
description = <<EOT
|
||||||
|
Map of datasources to create. Keys are datasource names.
|
||||||
|
Each datasource specifies type (prometheus/loki), keys to lookup URL/user/password,
|
||||||
|
and optional is_default (true/false).
|
||||||
|
EOT
|
||||||
|
type = map(object({
|
||||||
|
type = string # e.g., prometheus, loki
|
||||||
|
url_key = string # key for URL lookup in datasource_urls map
|
||||||
|
user_key = string # key for username lookup in datasource_users map
|
||||||
|
pass_key = string # key for password lookup in datasource_passwords map
|
||||||
|
is_default = optional(bool) # true if this datasource should be Grafana default
|
||||||
|
json_data = optional(map(any))
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "datasource_name" {
|
# Sensitive maps for URLs, usernames, passwords
|
||||||
type = string
|
variable "datasource_urls" {
|
||||||
|
description = "Map of datasource URLs, keyed by url_key"
|
||||||
|
type = map(string)
|
||||||
|
sensitive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "datasource_username" {
|
variable "datasource_users" {
|
||||||
type = string
|
description = "Map of datasource usernames, keyed by user_key"
|
||||||
sensitive = true
|
type = map(string)
|
||||||
|
sensitive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
variable "datasource_password" {
|
variable "datasource_passwords" {
|
||||||
type = string
|
description = "Map of datasource passwords, keyed by pass_key"
|
||||||
sensitive = true
|
type = map(string)
|
||||||
}
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{{ define "gchat-body-template" -}}
|
{{ define "google-chat-body-template" -}}
|
||||||
{{- $alerts := .Alerts }}
|
{{- $alerts := .Alerts }}
|
||||||
{{- if not $alerts }}{{ $alerts = . }}{{ end }}
|
{{- if not $alerts }}{{ $alerts = . }}{{ end }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{{ define "gchat-title-template" -}}
|
{{ define "google-chat-title-template" -}}
|
||||||
{{- if eq .Status "firing" -}}
|
{{- if eq .Status "firing" -}}
|
||||||
🔥 Firing:
|
🔥 Firing:
|
||||||
{{- else if eq .Status "resolved" -}}
|
{{- else if eq .Status "resolved" -}}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue