resource "google_monitoring_custom_service" "customsrv" {
for_each = var.custom_service_level
display_name = each.value.service_display_name
service_id = each.value.service_id
project = var.project_id
}
// Google Monitoring SLO objects can support many different metric types, for more info see our documenation.
resource "google_monitoring_slo" "custom_request_based_slo" {
for_each = var.custom_sli
service = google_monitoring_custom_service.customsrv[each.key].service_id
display_name = each.value.metric_display_name
goal = each.value.goal
rolling_period_days = each.value.rolling_period_days // Replacable with calendar_period = "DAY", "WEEK", "FORTNIGHT", or "MONTH"
request_based_sli {
// Alternate implementation could use distribution_cut instead of good_total_ratio.
good_total_ratio {
// Any combination of two elements: good_service_filter, bad_service_filter, total_service_filter.
good_service_filter = join(" AND ", each.value.good_service_filter)
total_service_filter = join(" AND ", each.value.total_service_filter)
}
}
depends_on = [ google_monitoring_custom_service.customsrv ]
}
Using .tfvars values:
custom_service_level = {
"composer-service" = {
service_id = "custom-srv-slos"
service_display_name = "My Custom SLO"
}
}
custom_sli = {
"composer-health" = {
metric_display_name = "test slo with service based SLI"
goal = 0.9
rolling_period_days = 28
window_period = "300s"
good_service_filter = [
"metric.type=\"composer.googleapis.com/workflow/run_count\"",
"resource.type=\"cloud_composer_workflow\"",
"metric.labels.state=\"success\"",
],
total_service_filter = [
"metric.type=\"composer.googleapis.com/workflow/run_count\"",
"resource.type=\"cloud_composer_workflow\"",
]
},
}
Variables used:
variable "custom_service_level" {
type = map(object({
service_id = string,
service_display_name = string,
}))
}
variable "custom_sli" {
type = map(object({
metric_display_name = string,
goal = number,
rolling_period_days = number,
good_service_filter = list(string),
total_service_filter = list(string)
# service = string
}))
}
Getting this error on plan:
│ Error: Invalid index
│
│ on main.tf line 600, in resource "google_monitoring_slo" "custom_request_based_slo":
│ 600: service = google_monitoring_custom_service.customsrv[each.key].service_id
│ ├────────────────
│ │ each.key is "composer-health"
│ │ google_monitoring_custom_service.customsrv is object with 1 attribute "composer-service"
│
│ The given key does not identify an element in this collection value.
╵
getting errors while creating alerts for above every above created map(object) both resource(1:1 relationship) using workaround1
resource "google_monitoring_alert_policy" "slo_alerts" {
project = var.project_id
display_name = var.slo_alert_display_name
combiner = "OR"
conditions {
display_name = var.slo_alert_display_name
condition_threshold {
filter = "select_slo_burn_rate(\"projects/${var.project_id}/services/${google_monitoring_custom_service.customsrv.service_id}/serviceLevelObjectives/${google_monitoring_slo.custom_request_based_slo.slo_id[]}\", \"3600s\")"
duration = var.duration
comparison = "COMPARISON_GT"
threshold_value = var.threshold_value
}
}
notification_channels = [
for channel in google_monitoring_notification_channel.basic : channel.name
]
documentation {
content = var.content
}
}
variables used:-
variable "enabled" {
type = bool
default = "true"
}
variable "slo_alert_display_name" {
type = string
default = "SLO Burn Rate Alert"
}
variable "content" {
type = string
default = "SLO burn for the past 60min exceeded x10 times the acceptable budget burn rate. Please verify from the console and take necessary action."
}
variable "threshold_value" {
type = number
default = 10
}
variable "duration" {
type = string
default = "0s"
}
error getting on plan
PS C:\tf-workspace testrepo\testrepo1> terraform plan
Acquiring state lock. This may take a few moments...
╷
│ Error: Reference to "each" in context without for_each
│
│ on logging-alert-policy.tf line 11, in resource "google_monitoring_alert_policy" "slo_alerts":
│ 11: filter = "select_slo_burn_rate(\"projects/${var.project_id}/services/${google_monitoring_custom_service.customsrv[each.key].service_id}/serviceLevelObjectives/${google_monitoring_slo.custom_request_based_slo[each.key].slo_id}\", \"3600s\")"
│
│ The "each" object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set.
╵
╷
│ Error: Reference to "each" in context without for_each
│
│ on logging-alert-policy.tf line 11, in resource "google_monitoring_alert_policy" "slo_alerts":
│ 11: filter = "select_slo_burn_rate(\"projects/${var.project_id}/services/${google_monitoring_custom_service.customsrv[each.key].service_id}/serviceLevelObjectives/${google_monitoring_slo.custom_request_based_slo[each.key].slo_id}\", \"3600s\")"
│
│ The "each" object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set.
how to use map(objects) for alert policy resource for each (customsrv and ustom_request_based_slo)
You are defining 2 maps, each one with different keys - composer-service
and composer-health
:
custom_service_level = {
"composer-service" = { # <--------------------- map key
# ...
}
}
custom_sli = {
"composer-health" = { # <--------------------- map key
# ...
}
}
The following line will throw an error because there is no google_monitoring_custom_service.customsrv
resource with key composer-health
:
service = google_monitoring_custom_service.customsrv[each.key].service_id
If there is a 1:1 relationship between custom_service_level
and custom_sli
you can use the same keys in both maps.
Working example using null_resource
:
variable "custom_service_level" {
type = map(object({
service_id = string,
service_display_name = string,
}))
default = {
"composer-001" = { // <-------------------- map key
service_id = "custom-srv-slos"
service_display_name = "My Custom SLO"
}
}
}
variable "custom_sli" {
type = map(object({
metric_display_name = string,
goal = number,
rolling_period_days = number,
good_service_filter = list(string),
total_service_filter = list(string)
}))
default = {
"composer-001" = { // <-------------------- same map key used in var.custom_service_level
metric_display_name = "test slo with service based SLI"
goal = 0.9
rolling_period_days = 28
window_period = "300s"
good_service_filter = [
"metric.type=\"composer.googleapis.com/workflow/run_count\"",
"resource.type=\"cloud_composer_workflow\"",
"metric.labels.state=\"success\"",
],
total_service_filter = [
"metric.type=\"composer.googleapis.com/workflow/run_count\"",
"resource.type=\"cloud_composer_workflow\"",
]
},
}
}
resource "null_resource" "customsrv" {
for_each = var.custom_service_level
triggers = {
display_name = each.value.service_display_name
service_id = each.value.service_id
}
}
resource "null_resource" "custom_request_based_slo" {
for_each = var.custom_sli
triggers = {
service = null_resource.customsrv[each.key].triggers.service_id
display_name = each.value.metric_display_name
goal = each.value.goal
rolling_period_days = each.value.rolling_period_days
}
}
Running terraform plan
:
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# null_resource.custom_request_based_slo["composer-001"] will be created
+ resource "null_resource" "custom_request_based_slo" {
+ id = (known after apply)
+ triggers = {
+ "display_name" = "test slo with service based SLI"
+ "goal" = "0.9"
+ "rolling_period_days" = "28"
+ "service" = "custom-srv-slos"
}
}
# null_resource.customsrv["composer-001"] will be created
+ resource "null_resource" "customsrv" {
+ id = (known after apply)
+ triggers = {
+ "display_name" = "My Custom SLO"
+ "service_id" = "custom-srv-slos"
}
}
Plan: 2 to add, 0 to change, 0 to destroy.
Add a custom_service_level
property to var.custom_sli
. This property must contain one of the map keys of var.custom_service_level
.
Working example using null_resource
:
variable "custom_service_level" {
type = map(object({
service_id = string,
service_display_name = string,
}))
default = {
"composer-service" = { // <-------------------- map key
service_id = "custom-srv-slos"
service_display_name = "My Custom SLO"
}
}
}
variable "custom_sli" {
type = map(object({
custom_service_level = string, // <------------------ new property
metric_display_name = string,
goal = number,
rolling_period_days = number,
good_service_filter = list(string),
total_service_filter = list(string)
}))
default = {
"composer-health" = {
custom_service_level = "composer-service" // <-------------------- map key from var.custom_service_level
metric_display_name = "test slo with service based SLI"
goal = 0.9
rolling_period_days = 28
window_period = "300s"
good_service_filter = [
"metric.type=\"composer.googleapis.com/workflow/run_count\"",
"resource.type=\"cloud_composer_workflow\"",
"metric.labels.state=\"success\"",
],
total_service_filter = [
"metric.type=\"composer.googleapis.com/workflow/run_count\"",
"resource.type=\"cloud_composer_workflow\"",
]
},
}
}
resource "null_resource" "customsrv" {
for_each = var.custom_service_level
triggers = {
display_name = each.value.service_display_name
service_id = each.value.service_id
}
}
resource "null_resource" "custom_request_based_slo" {
for_each = var.custom_sli
triggers = {
service = null_resource.customsrv[each.value.custom_service_level].triggers.service_id
display_name = each.value.metric_display_name
goal = each.value.goal
rolling_period_days = each.value.rolling_period_days
}
}
Running terraform plan
:
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# null_resource.custom_request_based_slo["composer-health"] will be created
+ resource "null_resource" "custom_request_based_slo" {
+ id = (known after apply)
+ triggers = {
+ "display_name" = "test slo with service based SLI"
+ "goal" = "0.9"
+ "rolling_period_days" = "28"
+ "service" = "custom-srv-slos"
}
}
# null_resource.customsrv["composer-service"] will be created
+ resource "null_resource" "customsrv" {
+ id = (known after apply)
+ triggers = {
+ "display_name" = "My Custom SLO"
+ "service_id" = "custom-srv-slos"
}
}
Plan: 2 to add, 0 to change, 0 to destroy.