diff --git a/docs/data-sources/slos.md b/docs/data-sources/slos.md
index 6c927052c..2cbab00e3 100644
--- a/docs/data-sources/slos.md
+++ b/docs/data-sources/slos.md
@@ -94,11 +94,20 @@ Read-Only:
Read-Only:
+- `advanced_options` (List of Object) (see [below for nested schema](#nestedobjatt--slos--alerting--advanced_options))
- `annotation` (List of Object) (see [below for nested schema](#nestedobjatt--slos--alerting--annotation))
- `fastburn` (List of Object) (see [below for nested schema](#nestedobjatt--slos--alerting--fastburn))
- `label` (List of Object) (see [below for nested schema](#nestedobjatt--slos--alerting--label))
- `slowburn` (List of Object) (see [below for nested schema](#nestedobjatt--slos--alerting--slowburn))
+
+### Nested Schema for `slos.alerting.advanced_options`
+
+Read-Only:
+
+- `min_failures` (Number)
+
+
### Nested Schema for `slos.alerting.annotation`
diff --git a/docs/resources/slo.md b/docs/resources/slo.md
index 3a728a462..cb6c8f35c 100644
--- a/docs/resources/slo.md
+++ b/docs/resources/slo.md
@@ -198,11 +198,20 @@ Optional:
Optional:
+- `advanced_options` (Block List, Max: 1) Advanced Options for Alert Rules (see [below for nested schema](#nestedblock--alerting--advanced_options))
- `annotation` (Block List) Annotations will be attached to all alerts generated by any of these rules. (see [below for nested schema](#nestedblock--alerting--annotation))
- `fastburn` (Block List, Max: 1) Alerting Rules generated for Fast Burn alerts (see [below for nested schema](#nestedblock--alerting--fastburn))
- `label` (Block List) Labels will be attached to all alerts generated by any of these rules. (see [below for nested schema](#nestedblock--alerting--label))
- `slowburn` (Block List, Max: 1) Alerting Rules generated for Slow Burn alerts (see [below for nested schema](#nestedblock--alerting--slowburn))
+
+### Nested Schema for `alerting.advanced_options`
+
+Optional:
+
+- `min_failures` (Number) Minimum number of failed events to trigger an alert
+
+
### Nested Schema for `alerting.annotation`
diff --git a/examples/resources/grafana_slo/resource_ratio_advanced_options.tf b/examples/resources/grafana_slo/resource_ratio_advanced_options.tf
new file mode 100644
index 000000000..8a10b8075
--- /dev/null
+++ b/examples/resources/grafana_slo/resource_ratio_advanced_options.tf
@@ -0,0 +1,49 @@
+resource "grafana_slo" "ratio_options" {
+ name = "Terraform Testing - Ratio Query"
+ description = "Terraform Description - Ratio Query"
+ query {
+ ratio {
+ success_metric = "kubelet_http_requests_total{status!~\"5..\"}"
+ total_metric = "kubelet_http_requests_total"
+ group_by_labels = ["job", "instance"]
+ }
+ type = "ratio"
+ }
+ objectives {
+ value = 0.995
+ window = "30d"
+ }
+ destination_datasource {
+ uid = "grafanacloud-prom"
+ }
+ label {
+ key = "slo"
+ value = "terraform"
+ }
+ alerting {
+ fastburn {
+ annotation {
+ key = "name"
+ value = "SLO Burn Rate Very High"
+ }
+ annotation {
+ key = "description"
+ value = "Error budget is burning too fast"
+ }
+ }
+
+ slowburn {
+ annotation {
+ key = "name"
+ value = "SLO Burn Rate High"
+ }
+ annotation {
+ key = "description"
+ value = "Error budget is burning too fast"
+ }
+ }
+ advanced_options {
+ min_failures = 10
+ }
+ }
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
index a432df54f..1538f9a10 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,7 @@ require (
github.com/grafana/grafana-com-public-clients/go/gcom v0.0.0-20240322153219-42c6a1d2bcab
github.com/grafana/grafana-openapi-client-go v0.0.0-20240523010106-657d101fcbd9
github.com/grafana/machine-learning-go-client v0.7.0
- github.com/grafana/slo-openapi-client/go v0.0.0-20240507015908-bf9e85638f2f
+ github.com/grafana/slo-openapi-client/go v0.0.0-20240626093634-e6741482b090
github.com/grafana/synthetic-monitoring-agent v0.24.3
github.com/grafana/synthetic-monitoring-api-go-client v0.8.0
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
diff --git a/go.sum b/go.sum
index a066eae60..24a4edfbf 100644
--- a/go.sum
+++ b/go.sum
@@ -148,8 +148,8 @@ github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF
github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls=
github.com/grafana/pyroscope-go/godeltaprof v0.1.7 h1:C11j63y7gymiW8VugJ9ZW0pWfxTZugdSJyC48olk5KY=
github.com/grafana/pyroscope-go/godeltaprof v0.1.7/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE=
-github.com/grafana/slo-openapi-client/go v0.0.0-20240507015908-bf9e85638f2f h1:aUDhr6LmO2W08tEP0Xe694DRfYZjlGp9kUnbeAF+194=
-github.com/grafana/slo-openapi-client/go v0.0.0-20240507015908-bf9e85638f2f/go.mod h1:HgbbeH2gFfCk2XZCrCly39DB13WkwWyQ+Ww+HTxePCs=
+github.com/grafana/slo-openapi-client/go v0.0.0-20240626093634-e6741482b090 h1:gDkJPpTL84zx+UkSY6a1pPlUm9aDEVBzPlVOkUbXmgM=
+github.com/grafana/slo-openapi-client/go v0.0.0-20240626093634-e6741482b090/go.mod h1:HgbbeH2gFfCk2XZCrCly39DB13WkwWyQ+Ww+HTxePCs=
github.com/grafana/synthetic-monitoring-agent v0.24.3 h1:+xscAsGZtWTNTNDxdYqqcz4w1tG6QPaOIgCONsVMoO8=
github.com/grafana/synthetic-monitoring-agent v0.24.3/go.mod h1:CJQmPtKRcJMjb/sDe6fDA4vyS2qFPElu0szI33nKlzk=
github.com/grafana/synthetic-monitoring-api-go-client v0.8.0 h1:Tm4MtwwYmPNInGfnj66l6j6KOshMkNV4emIVKJdlXMg=
diff --git a/internal/resources/slo/data_source_slo.go b/internal/resources/slo/data_source_slo.go
index 1a6880ed8..438cdc98b 100644
--- a/internal/resources/slo/data_source_slo.go
+++ b/internal/resources/slo/data_source_slo.go
@@ -190,6 +190,10 @@ func unpackAlerting(alertData *slo.SloV00Alerting) []map[string]interface{} {
alertObject["slowburn"] = unpackAlertingMetadata(*alertData.SlowBurn)
}
+ if alertData.AdvancedOptions != nil {
+ alertObject["advanced_options"] = unpackAdvancedOptions(*alertData.AdvancedOptions)
+ }
+
retAlertData = append(retAlertData, alertObject)
return retAlertData
}
@@ -212,6 +216,18 @@ func unpackAlertingMetadata(metaData slo.SloV00AlertingMetadata) []map[string]in
return retAlertMetaData
}
+func unpackAdvancedOptions(options slo.SloV00AdvancedOptions) []map[string]interface{} {
+ retAdvancedOptions := []map[string]interface{}{}
+ minFailuresStruct := make(map[string]interface{})
+
+ if options.MinFailures != nil {
+ minFailuresStruct["min_failures"] = int(*options.MinFailures)
+ }
+
+ retAdvancedOptions = append(retAdvancedOptions, minFailuresStruct)
+ return retAdvancedOptions
+}
+
func unpackDestinationDatasource(destinationDatasource *slo.SloV00DestinationDatasource) []map[string]interface{} {
retDestinationDatasources := []map[string]interface{}{}
diff --git a/internal/resources/slo/resource_slo.go b/internal/resources/slo/resource_slo.go
index 7365022c1..75678fdc3 100644
--- a/internal/resources/slo/resource_slo.go
+++ b/internal/resources/slo/resource_slo.go
@@ -221,6 +221,22 @@ Resource manages Grafana SLOs.
},
},
},
+ "advanced_options": {
+ Type: schema.TypeList,
+ MaxItems: 1,
+ Optional: true,
+ Description: "Advanced Options for Alert Rules",
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "min_failures": {
+ Type: schema.TypeInt,
+ Optional: true,
+ Description: "Minimum number of failed events to trigger an alert",
+ ValidateFunc: validation.IntAtLeast(0),
+ },
+ },
+ },
+ },
},
},
},
@@ -393,7 +409,6 @@ func packSloResource(d *schema.ResourceData) (slo.SloV00Slo, error) {
tfalerting = packAlerting(alert)
}
}
-
req.Alerting = &tfalerting
}
@@ -524,6 +539,7 @@ func packAlerting(tfAlerting map[string]interface{}) slo.SloV00Alerting {
var tfLabels []slo.SloV00Label
var tfFastBurn slo.SloV00AlertingMetadata
var tfSlowBurn slo.SloV00AlertingMetadata
+ var tfAdvancedOptions slo.SloV00AdvancedOptions
annots, ok := tfAlerting["annotation"].([]interface{})
if ok {
@@ -552,6 +568,22 @@ func packAlerting(tfAlerting map[string]interface{}) slo.SloV00Alerting {
SlowBurn: &tfSlowBurn,
}
+ // All options in advanced options will be optional
+ // Adding a second feature will need to make a better way of checking what is there
+ if failures := tfAlerting["advanced_options"]; failures != nil {
+ lf, ok := failures.([]interface{})
+ if ok && len(lf) > 0 {
+ lf2, ok := lf[0].(map[string]interface{})
+ if ok {
+ i64 := int64(lf2["min_failures"].(int))
+ tfAdvancedOptions = slo.SloV00AdvancedOptions{
+ MinFailures: &i64,
+ }
+ alerting.SetAdvancedOptions(tfAdvancedOptions)
+ }
+ }
+ }
+
return alerting
}
diff --git a/internal/resources/slo/resource_slo_test.go b/internal/resources/slo/resource_slo_test.go
index df97e8663..73697e4ae 100644
--- a/internal/resources/slo/resource_slo_test.go
+++ b/internal/resources/slo/resource_slo_test.go
@@ -94,6 +94,16 @@ func TestAccResourceSlo(t *testing.T) {
resource.TestCheckResourceAttr("grafana_slo.ratio", "query.0.ratio.0.group_by_labels.1", "instance"),
),
},
+ {
+ // Tests Advanced Options
+ Config: testutils.TestAccExample(t, "resources/grafana_slo/resource_ratio_advanced_options.tf"),
+ Check: resource.ComposeTestCheckFunc(
+ testAccSloCheckExists("grafana_slo.ratio_options", &slo),
+ testAlertingExists(true, "grafana_slo.ratio_options", &slo),
+ testAdvancedOptionsExists(true, "grafana_slo.ratio_options", &slo),
+ resource.TestCheckResourceAttr("grafana_slo.ratio_options", "alerting.0.advanced_options.0.min_failures", "10"),
+ ),
+ },
},
})
}
@@ -150,6 +160,30 @@ func testAlertingExists(expectation bool, rn string, slo *slo.SloV00Slo) resourc
}
}
+func testAdvancedOptionsExists(expectation bool, rn string, slo *slo.SloV00Slo) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs := s.RootModule().Resources[rn]
+ client := testutils.Provider.Meta().(*common.Client).SLOClient
+ req := client.DefaultAPI.V1SloIdGet(context.Background(), rs.Primary.ID)
+ gotSlo, _, err := req.Execute()
+
+ if err != nil {
+ return fmt.Errorf("error getting SLO: %s", err)
+ }
+ *slo = *gotSlo
+
+ if slo.Alerting.AdvancedOptions == nil && expectation == false {
+ return nil
+ }
+
+ if slo.Alerting.AdvancedOptions != nil && expectation == true {
+ return nil
+ }
+
+ return fmt.Errorf("SLO Advanced Options expectation mismatch")
+ }
+}
+
func testAccSloCheckDestroy(slo *slo.SloV00Slo) resource.TestCheckFunc {
return func(s *terraform.State) error {
client := testutils.Provider.Meta().(*common.Client).SLOClient