Skip to content

Commit 3961580

Browse files
Add support for promQL condition type in AlertPolicy (#8448) (#15301)
Signed-off-by: Modular Magician <[email protected]>
1 parent 9a9e5ea commit 3961580

File tree

4 files changed

+343
-0
lines changed

4 files changed

+343
-0
lines changed

.changelog/8448.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
monitoring: added `condition_prometheus_query_language` field to `google_monitoring_alert_policy` resource
3+
```

google/resource_monitoring_alert_policy_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func TestAccMonitoringAlertPolicy(t *testing.T) {
2323
"mql": testAccMonitoringAlertPolicy_mql,
2424
"log": testAccMonitoringAlertPolicy_log,
2525
"forecast": testAccMonitoringAlertPolicy_forecast,
26+
"promql": testAccMonitoringAlertPolicy_promql,
2627
}
2728

2829
for name, tc := range testCases {
@@ -212,6 +213,28 @@ func testAccMonitoringAlertPolicy_forecast(t *testing.T) {
212213
})
213214
}
214215

216+
func testAccMonitoringAlertPolicy_promql(t *testing.T) {
217+
218+
alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
219+
conditionName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
220+
221+
acctest.VcrTest(t, resource.TestCase{
222+
PreCheck: func() { acctest.AccTestPreCheck(t) },
223+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
224+
CheckDestroy: testAccCheckAlertPolicyDestroyProducer(t),
225+
Steps: []resource.TestStep{
226+
{
227+
Config: testAccMonitoringAlertPolicy_promqlCfg(alertName, conditionName),
228+
},
229+
{
230+
ResourceName: "google_monitoring_alert_policy.promql",
231+
ImportState: true,
232+
ImportStateVerify: true,
233+
},
234+
},
235+
})
236+
}
237+
215238
func testAccMonitoringAlertPolicy_basicCfg(alertName, conditionName, aligner, filter string) string {
216239
return fmt.Sprintf(`
217240
resource "google_monitoring_alert_policy" "basic" {
@@ -395,3 +418,33 @@ resource "google_monitoring_alert_policy" "forecast" {
395418
}
396419
`, alertName, conditionName, aligner, filter)
397420
}
421+
422+
func testAccMonitoringAlertPolicy_promqlCfg(alertName, conditionName string) string {
423+
return fmt.Sprintf(`
424+
resource "google_monitoring_alert_policy" "promql" {
425+
display_name = "%s"
426+
combiner = "OR"
427+
enabled = true
428+
429+
conditions {
430+
display_name = "%s"
431+
432+
condition_prometheus_query_language {
433+
query = "vector(1)"
434+
duration = "60s"
435+
evaluation_interval = "60s"
436+
labels = {
437+
"severity" = "page"
438+
}
439+
alert_rule = "AlwaysOn"
440+
rule_group = "abc"
441+
}
442+
}
443+
444+
documentation {
445+
content = "test content"
446+
mime_type = "text/markdown"
447+
}
448+
}
449+
`, alertName, conditionName)
450+
}

google/services/monitoring/resource_monitoring_alert_policy.go

+222
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,88 @@ condition to be triggered.`,
357357
},
358358
},
359359
},
360+
"condition_prometheus_query_language": {
361+
Type: schema.TypeList,
362+
Optional: true,
363+
Description: `A Monitoring Query Language query that outputs a boolean stream
364+
365+
A condition type that allows alert policies to be defined using
366+
Prometheus Query Language (PromQL).
367+
368+
The PrometheusQueryLanguageCondition message contains information
369+
from a Prometheus alerting rule and its associated rule group.`,
370+
MaxItems: 1,
371+
Elem: &schema.Resource{
372+
Schema: map[string]*schema.Schema{
373+
"evaluation_interval": {
374+
Type: schema.TypeString,
375+
Required: true,
376+
Description: `How often this rule should be evaluated. Must be a positive multiple
377+
of 30 seconds or missing. The default value is 30 seconds. If this
378+
PrometheusQueryLanguageCondition was generated from a Prometheus
379+
alerting rule, then this value should be taken from the enclosing
380+
rule group.`,
381+
},
382+
"query": {
383+
Type: schema.TypeString,
384+
Required: true,
385+
Description: `The PromQL expression to evaluate. Every evaluation cycle this
386+
expression is evaluated at the current time, and all resultant time
387+
series become pending/firing alerts. This field must not be empty.`,
388+
},
389+
"alert_rule": {
390+
Type: schema.TypeString,
391+
Optional: true,
392+
Description: `The alerting rule name of this alert in the corresponding Prometheus
393+
configuration file.
394+
395+
Some external tools may require this field to be populated correctly
396+
in order to refer to the original Prometheus configuration file.
397+
The rule group name and the alert name are necessary to update the
398+
relevant AlertPolicies in case the definition of the rule group changes
399+
in the future.
400+
401+
This field is optional. If this field is not empty, then it must be a
402+
valid Prometheus label name.`,
403+
},
404+
"duration": {
405+
Type: schema.TypeString,
406+
Optional: true,
407+
Description: `Alerts are considered firing once their PromQL expression evaluated
408+
to be "true" for this long. Alerts whose PromQL expression was not
409+
evaluated to be "true" for long enough are considered pending. The
410+
default value is zero. Must be zero or positive.`,
411+
},
412+
"labels": {
413+
Type: schema.TypeMap,
414+
Optional: true,
415+
Description: `Labels to add to or overwrite in the PromQL query result. Label names
416+
must be valid.
417+
418+
Label values can be templatized by using variables. The only available
419+
variable names are the names of the labels in the PromQL result, including
420+
"__name__" and "value". "labels" may be empty. This field is intended to be
421+
used for organizing and identifying the AlertPolicy`,
422+
Elem: &schema.Schema{Type: schema.TypeString},
423+
},
424+
"rule_group": {
425+
Type: schema.TypeString,
426+
Optional: true,
427+
Description: `The rule group name of this alert in the corresponding Prometheus
428+
configuration file.
429+
430+
Some external tools may require this field to be populated correctly
431+
in order to refer to the original Prometheus configuration file.
432+
The rule group name and the alert name are necessary to update the
433+
relevant AlertPolicies in case the definition of the rule group changes
434+
in the future.
435+
436+
This field is optional. If this field is not empty, then it must be a
437+
valid Prometheus label name.`,
438+
},
439+
},
440+
},
441+
},
360442
"condition_threshold": {
361443
Type: schema.TypeList,
362444
Optional: true,
@@ -1392,6 +1474,7 @@ func flattenMonitoringAlertPolicyConditions(v interface{}, d *schema.ResourceDat
13921474
"condition_threshold": flattenMonitoringAlertPolicyConditionsConditionThreshold(original["conditionThreshold"], d, config),
13931475
"display_name": flattenMonitoringAlertPolicyConditionsDisplayName(original["displayName"], d, config),
13941476
"condition_matched_log": flattenMonitoringAlertPolicyConditionsConditionMatchedLog(original["conditionMatchedLog"], d, config),
1477+
"condition_prometheus_query_language": flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage(original["conditionPrometheusQueryLanguage"], d, config),
13951478
})
13961479
}
13971480
return transformed
@@ -1776,6 +1859,53 @@ func flattenMonitoringAlertPolicyConditionsConditionMatchedLogLabelExtractors(v
17761859
return v
17771860
}
17781861

1862+
func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1863+
if v == nil {
1864+
return nil
1865+
}
1866+
original := v.(map[string]interface{})
1867+
if len(original) == 0 {
1868+
return nil
1869+
}
1870+
transformed := make(map[string]interface{})
1871+
transformed["query"] =
1872+
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageQuery(original["query"], d, config)
1873+
transformed["duration"] =
1874+
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageDuration(original["duration"], d, config)
1875+
transformed["evaluation_interval"] =
1876+
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageEvaluationInterval(original["evaluationInterval"], d, config)
1877+
transformed["labels"] =
1878+
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageLabels(original["labels"], d, config)
1879+
transformed["rule_group"] =
1880+
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageRuleGroup(original["ruleGroup"], d, config)
1881+
transformed["alert_rule"] =
1882+
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageAlertRule(original["alertRule"], d, config)
1883+
return []interface{}{transformed}
1884+
}
1885+
func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageQuery(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1886+
return v
1887+
}
1888+
1889+
func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageDuration(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1890+
return v
1891+
}
1892+
1893+
func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageEvaluationInterval(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1894+
return v
1895+
}
1896+
1897+
func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1898+
return v
1899+
}
1900+
1901+
func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageRuleGroup(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1902+
return v
1903+
}
1904+
1905+
func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageAlertRule(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
1906+
return v
1907+
}
1908+
17791909
func flattenMonitoringAlertPolicyNotificationChannels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
17801910
return v
17811911
}
@@ -1936,6 +2066,13 @@ func expandMonitoringAlertPolicyConditions(v interface{}, d tpgresource.Terrafor
19362066
transformed["conditionMatchedLog"] = transformedConditionMatchedLog
19372067
}
19382068

2069+
transformedConditionPrometheusQueryLanguage, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage(original["condition_prometheus_query_language"], d, config)
2070+
if err != nil {
2071+
return nil, err
2072+
} else if val := reflect.ValueOf(transformedConditionPrometheusQueryLanguage); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2073+
transformed["conditionPrometheusQueryLanguage"] = transformedConditionPrometheusQueryLanguage
2074+
}
2075+
19392076
req = append(req, transformed)
19402077
}
19412078
return req, nil
@@ -2498,6 +2635,91 @@ func expandMonitoringAlertPolicyConditionsConditionMatchedLogLabelExtractors(v i
24982635
return m, nil
24992636
}
25002637

2638+
func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2639+
l := v.([]interface{})
2640+
if len(l) == 0 || l[0] == nil {
2641+
return nil, nil
2642+
}
2643+
raw := l[0]
2644+
original := raw.(map[string]interface{})
2645+
transformed := make(map[string]interface{})
2646+
2647+
transformedQuery, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageQuery(original["query"], d, config)
2648+
if err != nil {
2649+
return nil, err
2650+
} else if val := reflect.ValueOf(transformedQuery); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2651+
transformed["query"] = transformedQuery
2652+
}
2653+
2654+
transformedDuration, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageDuration(original["duration"], d, config)
2655+
if err != nil {
2656+
return nil, err
2657+
} else if val := reflect.ValueOf(transformedDuration); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2658+
transformed["duration"] = transformedDuration
2659+
}
2660+
2661+
transformedEvaluationInterval, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageEvaluationInterval(original["evaluation_interval"], d, config)
2662+
if err != nil {
2663+
return nil, err
2664+
} else if val := reflect.ValueOf(transformedEvaluationInterval); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2665+
transformed["evaluationInterval"] = transformedEvaluationInterval
2666+
}
2667+
2668+
transformedLabels, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageLabels(original["labels"], d, config)
2669+
if err != nil {
2670+
return nil, err
2671+
} else if val := reflect.ValueOf(transformedLabels); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2672+
transformed["labels"] = transformedLabels
2673+
}
2674+
2675+
transformedRuleGroup, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageRuleGroup(original["rule_group"], d, config)
2676+
if err != nil {
2677+
return nil, err
2678+
} else if val := reflect.ValueOf(transformedRuleGroup); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2679+
transformed["ruleGroup"] = transformedRuleGroup
2680+
}
2681+
2682+
transformedAlertRule, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageAlertRule(original["alert_rule"], d, config)
2683+
if err != nil {
2684+
return nil, err
2685+
} else if val := reflect.ValueOf(transformedAlertRule); val.IsValid() && !tpgresource.IsEmptyValue(val) {
2686+
transformed["alertRule"] = transformedAlertRule
2687+
}
2688+
2689+
return transformed, nil
2690+
}
2691+
2692+
func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageQuery(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2693+
return v, nil
2694+
}
2695+
2696+
func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageDuration(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2697+
return v, nil
2698+
}
2699+
2700+
func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageEvaluationInterval(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2701+
return v, nil
2702+
}
2703+
2704+
func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
2705+
if v == nil {
2706+
return map[string]string{}, nil
2707+
}
2708+
m := make(map[string]string)
2709+
for k, val := range v.(map[string]interface{}) {
2710+
m[k] = val.(string)
2711+
}
2712+
return m, nil
2713+
}
2714+
2715+
func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageRuleGroup(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2716+
return v, nil
2717+
}
2718+
2719+
func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageAlertRule(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
2720+
return v, nil
2721+
}
2722+
25012723
func expandMonitoringAlertPolicyNotificationChannels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
25022724
return v, nil
25032725
}

0 commit comments

Comments
 (0)