Skip to content

Commit

Permalink
Add support for promQL condition type in AlertPolicy (#8448) (#15301)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
modular-magician authored Jul 26, 2023
1 parent 9a9e5ea commit 3961580
Show file tree
Hide file tree
Showing 4 changed files with 343 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/8448.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
monitoring: added `condition_prometheus_query_language` field to `google_monitoring_alert_policy` resource
```
53 changes: 53 additions & 0 deletions google/resource_monitoring_alert_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestAccMonitoringAlertPolicy(t *testing.T) {
"mql": testAccMonitoringAlertPolicy_mql,
"log": testAccMonitoringAlertPolicy_log,
"forecast": testAccMonitoringAlertPolicy_forecast,
"promql": testAccMonitoringAlertPolicy_promql,
}

for name, tc := range testCases {
Expand Down Expand Up @@ -212,6 +213,28 @@ func testAccMonitoringAlertPolicy_forecast(t *testing.T) {
})
}

func testAccMonitoringAlertPolicy_promql(t *testing.T) {

alertName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
conditionName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckAlertPolicyDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccMonitoringAlertPolicy_promqlCfg(alertName, conditionName),
},
{
ResourceName: "google_monitoring_alert_policy.promql",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccMonitoringAlertPolicy_basicCfg(alertName, conditionName, aligner, filter string) string {
return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "basic" {
Expand Down Expand Up @@ -395,3 +418,33 @@ resource "google_monitoring_alert_policy" "forecast" {
}
`, alertName, conditionName, aligner, filter)
}

func testAccMonitoringAlertPolicy_promqlCfg(alertName, conditionName string) string {
return fmt.Sprintf(`
resource "google_monitoring_alert_policy" "promql" {
display_name = "%s"
combiner = "OR"
enabled = true
conditions {
display_name = "%s"
condition_prometheus_query_language {
query = "vector(1)"
duration = "60s"
evaluation_interval = "60s"
labels = {
"severity" = "page"
}
alert_rule = "AlwaysOn"
rule_group = "abc"
}
}
documentation {
content = "test content"
mime_type = "text/markdown"
}
}
`, alertName, conditionName)
}
222 changes: 222 additions & 0 deletions google/services/monitoring/resource_monitoring_alert_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,88 @@ condition to be triggered.`,
},
},
},
"condition_prometheus_query_language": {
Type: schema.TypeList,
Optional: true,
Description: `A Monitoring Query Language query that outputs a boolean stream
A condition type that allows alert policies to be defined using
Prometheus Query Language (PromQL).
The PrometheusQueryLanguageCondition message contains information
from a Prometheus alerting rule and its associated rule group.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"evaluation_interval": {
Type: schema.TypeString,
Required: true,
Description: `How often this rule should be evaluated. Must be a positive multiple
of 30 seconds or missing. The default value is 30 seconds. If this
PrometheusQueryLanguageCondition was generated from a Prometheus
alerting rule, then this value should be taken from the enclosing
rule group.`,
},
"query": {
Type: schema.TypeString,
Required: true,
Description: `The PromQL expression to evaluate. Every evaluation cycle this
expression is evaluated at the current time, and all resultant time
series become pending/firing alerts. This field must not be empty.`,
},
"alert_rule": {
Type: schema.TypeString,
Optional: true,
Description: `The alerting rule name of this alert in the corresponding Prometheus
configuration file.
Some external tools may require this field to be populated correctly
in order to refer to the original Prometheus configuration file.
The rule group name and the alert name are necessary to update the
relevant AlertPolicies in case the definition of the rule group changes
in the future.
This field is optional. If this field is not empty, then it must be a
valid Prometheus label name.`,
},
"duration": {
Type: schema.TypeString,
Optional: true,
Description: `Alerts are considered firing once their PromQL expression evaluated
to be "true" for this long. Alerts whose PromQL expression was not
evaluated to be "true" for long enough are considered pending. The
default value is zero. Must be zero or positive.`,
},
"labels": {
Type: schema.TypeMap,
Optional: true,
Description: `Labels to add to or overwrite in the PromQL query result. Label names
must be valid.
Label values can be templatized by using variables. The only available
variable names are the names of the labels in the PromQL result, including
"__name__" and "value". "labels" may be empty. This field is intended to be
used for organizing and identifying the AlertPolicy`,
Elem: &schema.Schema{Type: schema.TypeString},
},
"rule_group": {
Type: schema.TypeString,
Optional: true,
Description: `The rule group name of this alert in the corresponding Prometheus
configuration file.
Some external tools may require this field to be populated correctly
in order to refer to the original Prometheus configuration file.
The rule group name and the alert name are necessary to update the
relevant AlertPolicies in case the definition of the rule group changes
in the future.
This field is optional. If this field is not empty, then it must be a
valid Prometheus label name.`,
},
},
},
},
"condition_threshold": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -1392,6 +1474,7 @@ func flattenMonitoringAlertPolicyConditions(v interface{}, d *schema.ResourceDat
"condition_threshold": flattenMonitoringAlertPolicyConditionsConditionThreshold(original["conditionThreshold"], d, config),
"display_name": flattenMonitoringAlertPolicyConditionsDisplayName(original["displayName"], d, config),
"condition_matched_log": flattenMonitoringAlertPolicyConditionsConditionMatchedLog(original["conditionMatchedLog"], d, config),
"condition_prometheus_query_language": flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage(original["conditionPrometheusQueryLanguage"], d, config),
})
}
return transformed
Expand Down Expand Up @@ -1776,6 +1859,53 @@ func flattenMonitoringAlertPolicyConditionsConditionMatchedLogLabelExtractors(v
return v
}

func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["query"] =
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageQuery(original["query"], d, config)
transformed["duration"] =
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageDuration(original["duration"], d, config)
transformed["evaluation_interval"] =
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageEvaluationInterval(original["evaluationInterval"], d, config)
transformed["labels"] =
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageLabels(original["labels"], d, config)
transformed["rule_group"] =
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageRuleGroup(original["ruleGroup"], d, config)
transformed["alert_rule"] =
flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageAlertRule(original["alertRule"], d, config)
return []interface{}{transformed}
}
func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageQuery(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageDuration(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageEvaluationInterval(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageRuleGroup(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageAlertRule(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenMonitoringAlertPolicyNotificationChannels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
Expand Down Expand Up @@ -1936,6 +2066,13 @@ func expandMonitoringAlertPolicyConditions(v interface{}, d tpgresource.Terrafor
transformed["conditionMatchedLog"] = transformedConditionMatchedLog
}

transformedConditionPrometheusQueryLanguage, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage(original["condition_prometheus_query_language"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedConditionPrometheusQueryLanguage); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["conditionPrometheusQueryLanguage"] = transformedConditionPrometheusQueryLanguage
}

req = append(req, transformed)
}
return req, nil
Expand Down Expand Up @@ -2498,6 +2635,91 @@ func expandMonitoringAlertPolicyConditionsConditionMatchedLogLabelExtractors(v i
return m, nil
}

func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedQuery, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageQuery(original["query"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedQuery); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["query"] = transformedQuery
}

transformedDuration, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageDuration(original["duration"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedDuration); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["duration"] = transformedDuration
}

transformedEvaluationInterval, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageEvaluationInterval(original["evaluation_interval"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedEvaluationInterval); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["evaluationInterval"] = transformedEvaluationInterval
}

transformedLabels, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageLabels(original["labels"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedLabels); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["labels"] = transformedLabels
}

transformedRuleGroup, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageRuleGroup(original["rule_group"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedRuleGroup); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["ruleGroup"] = transformedRuleGroup
}

transformedAlertRule, err := expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageAlertRule(original["alert_rule"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedAlertRule); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["alertRule"] = transformedAlertRule
}

return transformed, nil
}

func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageQuery(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageDuration(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageEvaluationInterval(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
}
m := make(map[string]string)
for k, val := range v.(map[string]interface{}) {
m[k] = val.(string)
}
return m, nil
}

func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageRuleGroup(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyConditionsConditionPrometheusQueryLanguageAlertRule(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandMonitoringAlertPolicyNotificationChannels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
Expand Down
Loading

0 comments on commit 3961580

Please sign in to comment.