Alerting: Add MissingSeriesEvalsToResolve to the APIs (#102150)

What is this feature?

A follow-up for #101184, adds AlertRule.MissingSeriesEvalsToResolve to the APIs.

missing_series_evals_to_resolve must be specified too and it must be > 0.

POST /api/ruler/grafana/api/v1/rules/{folderUID} works in the following way:

    If missing_series_evals_to_resolve is not sent or null, the rule keeps its existing value
    If missing_series_evals_to_resolve > 0: updates to that value
    If missing_series_evals_to_resolve = 0: resets to default (nil).
    AlertRule.MissingSeriesEvalsToResolve can't be 0, so I used it to reset

In the Provisioning API, the value is just set if present and > 0. Otherwise it's reset:

PUT to /api/v1/provisioning/alert-rules/{UID}:

    If missing_series_evals_to_resolve is nil, it's reset to the default value
    If missing_series_evals_to_resolve > 0, it's updated
This commit is contained in:
Alexander Akhmetov
2025-03-26 13:34:53 +01:00
committed by GitHub
parent f2fc1d8575
commit f49a88ab72
17 changed files with 462 additions and 116 deletions
@@ -13,6 +13,7 @@ import (
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
prommodels "github.com/prometheus/common/model"
)
@@ -65,14 +66,15 @@ func ValidateRuleNode(
queries := AlertQueriesFromApiAlertQueries(ruleNode.GrafanaManagedAlert.Data)
newAlertRule := ngmodels.AlertRule{
OrgID: orgId,
Title: ruleNode.GrafanaManagedAlert.Title,
Condition: ruleNode.GrafanaManagedAlert.Condition,
Data: queries,
UID: ruleNode.GrafanaManagedAlert.UID,
IntervalSeconds: intervalSeconds,
NamespaceUID: namespaceUID,
RuleGroup: groupName,
OrgID: orgId,
Title: ruleNode.GrafanaManagedAlert.Title,
Condition: ruleNode.GrafanaManagedAlert.Condition,
Data: queries,
UID: ruleNode.GrafanaManagedAlert.UID,
IntervalSeconds: intervalSeconds,
NamespaceUID: namespaceUID,
RuleGroup: groupName,
MissingSeriesEvalsToResolve: ruleNode.GrafanaManagedAlert.MissingSeriesEvalsToResolve,
}
if isRecordingRule {
@@ -152,6 +154,11 @@ func validateAlertingRuleFields(in *apimodels.PostableExtendedRuleNode, newRule
}
}
newRule.MissingSeriesEvalsToResolve, err = validateMissingSeriesEvalsToResolve(in)
if err != nil {
return ngmodels.AlertRule{}, err
}
newRule.For, err = validateForInterval(in)
if err != nil {
return ngmodels.AlertRule{}, err
@@ -293,6 +300,29 @@ func validateKeepFiringForInterval(ruleNode *apimodels.PostableExtendedRuleNode)
return duration, nil
}
// validateMissingSeriesEvalsToResolve validates MissingSeriesEvalsToResolve and converts it to *int.
// If the ruleNode.GrafanaManagedAlert.MissingSeriesEvalsToResolve is:
// - == 0, returns nil (reset to default)
// - == nil && UID == "", returns nil (new rule)
// - == nil && UID != "", returns -1 (existing rule)
func validateMissingSeriesEvalsToResolve(ruleNode *apimodels.PostableExtendedRuleNode) (*int, error) {
if ruleNode.GrafanaManagedAlert.MissingSeriesEvalsToResolve == nil {
if ruleNode.GrafanaManagedAlert.UID != "" {
return util.Pointer(-1), nil // will be patched later with the real value of the current version of the rule
}
return nil, nil // if it's a new rule, use nil as the default
}
v := ruleNode.GrafanaManagedAlert.MissingSeriesEvalsToResolve
if *v == 0 {
return nil, nil // allow to reset the value to default when 0 is sent
} else if *v < 0 {
return nil, fmt.Errorf("field `missing_series_evals_to_resolve` cannot be negative [%v]. 0 or any positive number are allowed", *v)
}
return v, nil
}
// ValidateRuleGroup validates API model (definitions.PostableRuleGroupConfig) and converts it to a collection of models.AlertRule.
// Returns a slice that contains all rules described by API model or error if either group specification or an alert definition is not valid.
// It also returns a map containing current existing alerts that don't contain the is_paused field in the body of the call.