mirror of https://github.com/grafana/grafana.git
Alerting: Update Alert Rule to use int64 for MissingSeriesEvalsToResolve (#109306)
This commit is contained in:
parent
e36402a121
commit
16f8359d35
|
@ -403,7 +403,7 @@ func TestIntegrationProvisioningApi(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("PUT without MissingSeriesEvalsToResolve clears the field", func(t *testing.T) {
|
||||
oldValue := util.Pointer(5)
|
||||
oldValue := util.Pointer[int64](5)
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
rule := createTestAlertRule("rule", 1)
|
||||
|
@ -420,8 +420,8 @@ func TestIntegrationProvisioningApi(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("PUT with MissingSeriesEvalsToResolve updates the value", func(t *testing.T) {
|
||||
oldValue := util.Pointer(5)
|
||||
newValue := util.Pointer(10)
|
||||
oldValue := util.Pointer[int64](5)
|
||||
newValue := util.Pointer[int64](10)
|
||||
sut := createProvisioningSrvSut(t)
|
||||
rc := createTestRequestCtx()
|
||||
rule := createTestAlertRule("rule", 1)
|
||||
|
@ -657,12 +657,12 @@ func TestIntegrationProvisioningApi(t *testing.T) {
|
|||
require.Nil(t, updated.Rules[0].MissingSeriesEvalsToResolve)
|
||||
|
||||
// Put the same group with a new value
|
||||
group.Rules[0].MissingSeriesEvalsToResolve = util.Pointer(5)
|
||||
group.Rules[0].MissingSeriesEvalsToResolve = util.Pointer[int64](5)
|
||||
response = sut.RoutePutAlertRuleGroup(&rc, group, "folder-uid", group.Title)
|
||||
require.Equal(t, 200, response.Status())
|
||||
updated = deserializeRuleGroup(t, response.Body())
|
||||
require.NotNil(t, updated.Rules[0].MissingSeriesEvalsToResolve)
|
||||
require.Equal(t, 5, *updated.Rules[0].MissingSeriesEvalsToResolve)
|
||||
require.Equal(t, int64(5), *updated.Rules[0].MissingSeriesEvalsToResolve)
|
||||
|
||||
// Reset the value again
|
||||
group.Rules[0].MissingSeriesEvalsToResolve = nil
|
||||
|
|
|
@ -593,7 +593,7 @@ type PostableGrafanaRule struct {
|
|||
// If set to 0, the value is reset to the default.
|
||||
// required: false
|
||||
// example: 3
|
||||
MissingSeriesEvalsToResolve *int `json:"missing_series_evals_to_resolve,omitempty" yaml:"missing_series_evals_to_resolve,omitempty"`
|
||||
MissingSeriesEvalsToResolve *int64 `json:"missing_series_evals_to_resolve,omitempty" yaml:"missing_series_evals_to_resolve,omitempty"`
|
||||
}
|
||||
|
||||
// swagger:model
|
||||
|
@ -616,7 +616,7 @@ type GettableGrafanaRule struct {
|
|||
Record *Record `json:"record,omitempty" yaml:"record,omitempty"`
|
||||
Metadata *AlertRuleMetadata `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
GUID string `json:"guid" yaml:"guid"`
|
||||
MissingSeriesEvalsToResolve *int `json:"missing_series_evals_to_resolve,omitempty" yaml:"missing_series_evals_to_resolve,omitempty"`
|
||||
MissingSeriesEvalsToResolve *int64 `json:"missing_series_evals_to_resolve,omitempty" yaml:"missing_series_evals_to_resolve,omitempty"`
|
||||
}
|
||||
|
||||
// UserInfo represents user-related information, including a unique identifier and a name.
|
||||
|
|
|
@ -174,7 +174,7 @@ type ProvisionedAlertRule struct {
|
|||
// example: {"metric":"grafana_alerts_ratio", "from":"A"}
|
||||
Record *Record `json:"record"`
|
||||
// example: 2
|
||||
MissingSeriesEvalsToResolve *int `json:"missingSeriesEvalsToResolve,omitempty"`
|
||||
MissingSeriesEvalsToResolve *int64 `json:"missingSeriesEvalsToResolve,omitempty"`
|
||||
}
|
||||
|
||||
// swagger:route GET /v1/provisioning/folder/{FolderUID}/rule-groups/{Group} provisioning stable RouteGetAlertRuleGroup
|
||||
|
@ -284,7 +284,7 @@ type AlertRuleExport struct {
|
|||
IsPaused bool `json:"isPaused" yaml:"isPaused" hcl:"is_paused"`
|
||||
NotificationSettings *AlertRuleNotificationSettingsExport `json:"notification_settings,omitempty" yaml:"notification_settings,omitempty" hcl:"notification_settings,block"`
|
||||
Record *AlertRuleRecordExport `json:"record,omitempty" yaml:"record,omitempty" hcl:"record,block"`
|
||||
MissingSeriesEvalsToResolve *int `json:"missing_series_evals_to_resolve,omitempty" yaml:"missing_series_evals_to_resolve,omitempty" hcl:"missing_series_evals_to_resolve"`
|
||||
MissingSeriesEvalsToResolve *int64 `json:"missing_series_evals_to_resolve,omitempty" yaml:"missing_series_evals_to_resolve,omitempty" hcl:"missing_series_evals_to_resolve"`
|
||||
}
|
||||
|
||||
// AlertQueryExport is the provisioned export of models.AlertQuery.
|
||||
|
|
|
@ -299,10 +299,10 @@ func validateKeepFiringForInterval(ruleNode *apimodels.PostableExtendedRuleNode)
|
|||
// - == 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) {
|
||||
func validateMissingSeriesEvalsToResolve(ruleNode *apimodels.PostableExtendedRuleNode) (*int64, 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 util.Pointer[int64](-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
|
||||
}
|
||||
|
|
|
@ -304,7 +304,7 @@ type AlertRule struct {
|
|||
// required before resolving an alert state (a dimension) when data is missing.
|
||||
// If nil, alerts resolve after 2 missing evaluation intervals
|
||||
// (i.e., resolution occurs during the second evaluation where data is absent).
|
||||
MissingSeriesEvalsToResolve *int
|
||||
MissingSeriesEvalsToResolve *int64
|
||||
}
|
||||
|
||||
type AlertRuleMetadata struct {
|
||||
|
@ -598,7 +598,7 @@ func (alertRule *AlertRule) GetGroupKey() AlertRuleGroupKey {
|
|||
// to wait before resolving an alert rule instance when its data is missing.
|
||||
// If not configured, it returns the default value (2), which means the alert
|
||||
// resolves after missing for two evaluation intervals.
|
||||
func (alertRule *AlertRule) GetMissingSeriesEvalsToResolve() int {
|
||||
func (alertRule *AlertRule) GetMissingSeriesEvalsToResolve() int64 {
|
||||
if alertRule.MissingSeriesEvalsToResolve == nil {
|
||||
return 2 // default value
|
||||
}
|
||||
|
|
|
@ -554,8 +554,8 @@ func TestDiff(t *testing.T) {
|
|||
if rule1.MissingSeriesEvalsToResolve != rule2.MissingSeriesEvalsToResolve {
|
||||
diff := diffs.GetDiffsForField("MissingSeriesEvalsToResolve")
|
||||
assert.Len(t, diff, 1)
|
||||
assert.Equal(t, *rule1.MissingSeriesEvalsToResolve, int(diff[0].Left.Int()))
|
||||
assert.Equal(t, *rule2.MissingSeriesEvalsToResolve, int(diff[0].Right.Int()))
|
||||
assert.Equal(t, *rule1.MissingSeriesEvalsToResolve, diff[0].Left.Int())
|
||||
assert.Equal(t, *rule2.MissingSeriesEvalsToResolve, diff[0].Right.Int())
|
||||
difCnt++
|
||||
}
|
||||
|
||||
|
@ -1001,14 +1001,14 @@ func TestAlertRuleGetMissingSeriesEvalsToResolve(t *testing.T) {
|
|||
t.Run("should return the default 2 if MissingSeriesEvalsToResolve is nil", func(t *testing.T) {
|
||||
rule := RuleGen.GenerateRef()
|
||||
rule.MissingSeriesEvalsToResolve = nil
|
||||
require.Equal(t, 2, rule.GetMissingSeriesEvalsToResolve())
|
||||
require.Equal(t, int64(2), rule.GetMissingSeriesEvalsToResolve())
|
||||
})
|
||||
|
||||
t.Run("should return the correct value", func(t *testing.T) {
|
||||
rule := RuleGen.With(
|
||||
RuleMuts.WithMissingSeriesEvalsToResolve(3),
|
||||
).GenerateRef()
|
||||
require.Equal(t, 3, rule.GetMissingSeriesEvalsToResolve())
|
||||
require.Equal(t, int64(3), rule.GetMissingSeriesEvalsToResolve())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1113,7 +1113,7 @@ func TestValidateAlertRule(t *testing.T) {
|
|||
t.Run("missingSeriesEvalsToResolve", func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
missingSeriesEvalsToResolve *int
|
||||
missingSeriesEvalsToResolve *int64
|
||||
expectedErrorContains string
|
||||
}{
|
||||
{
|
||||
|
@ -1122,17 +1122,17 @@ func TestValidateAlertRule(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "should reject negative value",
|
||||
missingSeriesEvalsToResolve: util.Pointer(-1),
|
||||
missingSeriesEvalsToResolve: util.Pointer[int64](-1),
|
||||
expectedErrorContains: "field `missing_series_evals_to_resolve` must be greater than 0",
|
||||
},
|
||||
{
|
||||
name: "should reject 0",
|
||||
missingSeriesEvalsToResolve: util.Pointer(0),
|
||||
missingSeriesEvalsToResolve: util.Pointer[int64](0),
|
||||
expectedErrorContains: "field `missing_series_evals_to_resolve` must be greater than 0",
|
||||
},
|
||||
{
|
||||
name: "should accept positive value",
|
||||
missingSeriesEvalsToResolve: util.Pointer(2),
|
||||
missingSeriesEvalsToResolve: util.Pointer[int64](2),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ func (g *AlertRuleGenerator) Generate() AlertRule {
|
|||
Labels: labels,
|
||||
NotificationSettings: ns,
|
||||
Metadata: GenerateMetadata(),
|
||||
MissingSeriesEvalsToResolve: util.Pointer(2),
|
||||
MissingSeriesEvalsToResolve: util.Pointer[int64](2),
|
||||
}
|
||||
|
||||
for _, mutator := range g.mutators {
|
||||
|
@ -514,12 +514,12 @@ func (a *AlertRuleMutators) WithSameGroup() AlertRuleMutator {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *AlertRuleMutators) WithMissingSeriesEvalsToResolve(timesOfInterval int) AlertRuleMutator {
|
||||
func (a *AlertRuleMutators) WithMissingSeriesEvalsToResolve(timesOfInterval int64) AlertRuleMutator {
|
||||
return func(rule *AlertRule) {
|
||||
if timesOfInterval <= 0 {
|
||||
panic("timesOfInterval must be greater than 0")
|
||||
}
|
||||
rule.MissingSeriesEvalsToResolve = util.Pointer(timesOfInterval)
|
||||
rule.MissingSeriesEvalsToResolve = util.Pointer[int64](timesOfInterval)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -275,7 +275,7 @@ func (p *Converter) convertRule(orgID int64, namespaceUID string, promGroup Prom
|
|||
// Prometheus resolves alerts as soon as the series disappears.
|
||||
// By setting this value to 1 we ensure that the alert is resolved on the first evaluation
|
||||
// that doesn't have the series.
|
||||
MissingSeriesEvalsToResolve: util.Pointer(1),
|
||||
MissingSeriesEvalsToResolve: util.Pointer[int64](1),
|
||||
}
|
||||
|
||||
if !isRecordingRule {
|
||||
|
|
|
@ -358,7 +358,7 @@ func TestPrometheusRulesToGrafana(t *testing.T) {
|
|||
|
||||
require.Equal(t, models.Duration(evalOffset), grafanaRule.Data[0].RelativeTimeRange.To)
|
||||
require.Equal(t, models.Duration(10*time.Minute+evalOffset), grafanaRule.Data[0].RelativeTimeRange.From)
|
||||
require.Equal(t, util.Pointer(1), grafanaRule.MissingSeriesEvalsToResolve)
|
||||
require.Equal(t, util.Pointer(int64(1)), grafanaRule.MissingSeriesEvalsToResolve)
|
||||
|
||||
require.Equal(t, models.OkErrState, grafanaRule.ExecErrState)
|
||||
require.Equal(t, models.OK, grafanaRule.NoDataState)
|
||||
|
|
|
@ -214,7 +214,7 @@ func TestRuleWithFolderFingerprint(t *testing.T) {
|
|||
SimplifiedNotificationsSection: false,
|
||||
},
|
||||
},
|
||||
MissingSeriesEvalsToResolve: util.Pointer(2),
|
||||
MissingSeriesEvalsToResolve: util.Pointer[int64](2),
|
||||
}
|
||||
r2 := &models.AlertRule{
|
||||
ID: 2,
|
||||
|
@ -260,7 +260,7 @@ func TestRuleWithFolderFingerprint(t *testing.T) {
|
|||
SimplifiedQueryAndExpressionsSection: true,
|
||||
},
|
||||
},
|
||||
MissingSeriesEvalsToResolve: util.Pointer(1),
|
||||
MissingSeriesEvalsToResolve: util.Pointer[int64](1),
|
||||
}
|
||||
|
||||
excludedFields := map[string]struct{}{
|
||||
|
|
|
@ -587,13 +587,13 @@ func (st *Manager) processMissingSeriesStates(logger log.Logger, evaluatedAt tim
|
|||
|
||||
// stateIsStale determines whether the evaluation state is considered stale.
|
||||
// A state is considered stale if the data has been missing for at least missingSeriesEvalsToResolve evaluation intervals.
|
||||
func stateIsStale(evaluatedAt time.Time, lastEval time.Time, intervalSeconds int64, missingSeriesEvalsToResolve int) bool {
|
||||
func stateIsStale(evaluatedAt time.Time, lastEval time.Time, intervalSeconds int64, missingSeriesEvalsToResolve int64) bool {
|
||||
// If the last evaluation time equals the current evaluation time, the state is not stale.
|
||||
if evaluatedAt.Equal(lastEval) {
|
||||
return false
|
||||
}
|
||||
|
||||
resolveIfMissingDuration := time.Duration(int64(missingSeriesEvalsToResolve)*intervalSeconds) * time.Second
|
||||
resolveIfMissingDuration := time.Duration(missingSeriesEvalsToResolve*intervalSeconds) * time.Second
|
||||
|
||||
// timeSinceLastEval >= resolveIfMissingDuration
|
||||
return evaluatedAt.Sub(lastEval) >= resolveIfMissingDuration
|
||||
|
|
|
@ -39,7 +39,7 @@ func TestStateIsStale(t *testing.T) {
|
|||
name string
|
||||
lastEvaluation time.Time
|
||||
expectedResult bool
|
||||
missingSeriesEvalsToResolve int
|
||||
missingSeriesEvalsToResolve int64
|
||||
}{
|
||||
{
|
||||
name: "false if last evaluation is now",
|
||||
|
|
|
@ -30,7 +30,7 @@ type alertRule struct {
|
|||
IsPaused bool
|
||||
NotificationSettings string `xorm:"notification_settings"`
|
||||
Metadata string `xorm:"metadata"`
|
||||
MissingSeriesEvalsToResolve *int `xorm:"missing_series_evals_to_resolve"`
|
||||
MissingSeriesEvalsToResolve *int64 `xorm:"missing_series_evals_to_resolve"`
|
||||
}
|
||||
|
||||
func (a alertRule) TableName() string {
|
||||
|
@ -68,7 +68,7 @@ type alertRuleVersion struct {
|
|||
IsPaused bool
|
||||
NotificationSettings string `xorm:"notification_settings"`
|
||||
Metadata string `xorm:"metadata"`
|
||||
MissingSeriesEvalsToResolve *int `xorm:"missing_series_evals_to_resolve"`
|
||||
MissingSeriesEvalsToResolve *int64 `xorm:"missing_series_evals_to_resolve"`
|
||||
}
|
||||
|
||||
// EqualSpec compares two alertRuleVersion objects for equality based on their specifications and returns true if they match.
|
||||
|
|
|
@ -661,7 +661,7 @@ func TestIntegrationProvisioningRules(t *testing.T) {
|
|||
Model: json.RawMessage([]byte(`{"type":"math","expression":"2 + 3 \u003e 1"}`)),
|
||||
},
|
||||
},
|
||||
MissingSeriesEvalsToResolve: util.Pointer(3),
|
||||
MissingSeriesEvalsToResolve: util.Pointer[int64](3),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -676,7 +676,7 @@ func TestIntegrationProvisioningRules(t *testing.T) {
|
|||
for _, rule := range result.Rules {
|
||||
require.NotEmpty(t, rule.UID)
|
||||
if rule.UID == "rule3" {
|
||||
require.Equal(t, 3, *rule.MissingSeriesEvalsToResolve)
|
||||
require.Equal(t, int64(3), *rule.MissingSeriesEvalsToResolve)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1761,42 +1761,42 @@ func TestIntegrationRuleUpdate(t *testing.T) {
|
|||
t.Run("missing_series_evals_to_resolve", func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
initialValue *int
|
||||
updatedValue *int
|
||||
expectedValue *int
|
||||
initialValue *int64
|
||||
updatedValue *int64
|
||||
expectedValue *int64
|
||||
expectedStatus int
|
||||
}{
|
||||
{
|
||||
name: "should be able to set missing_series_evals_to_resolve to 5",
|
||||
initialValue: nil,
|
||||
updatedValue: util.Pointer(5),
|
||||
expectedValue: util.Pointer(5),
|
||||
updatedValue: util.Pointer[int64](5),
|
||||
expectedValue: util.Pointer[int64](5),
|
||||
expectedStatus: http.StatusAccepted,
|
||||
},
|
||||
{
|
||||
name: "should be able to update missing_series_evals_to_resolve",
|
||||
initialValue: util.Pointer(1),
|
||||
updatedValue: util.Pointer(2),
|
||||
expectedValue: util.Pointer(2),
|
||||
initialValue: util.Pointer[int64](1),
|
||||
updatedValue: util.Pointer[int64](2),
|
||||
expectedValue: util.Pointer[int64](2),
|
||||
expectedStatus: http.StatusAccepted,
|
||||
},
|
||||
{
|
||||
name: "should preserve missing_series_evals_to_resolve when it's set nil",
|
||||
initialValue: util.Pointer(5),
|
||||
initialValue: util.Pointer[int64](5),
|
||||
updatedValue: nil,
|
||||
expectedValue: util.Pointer(5),
|
||||
expectedValue: util.Pointer[int64](5),
|
||||
expectedStatus: http.StatusAccepted,
|
||||
},
|
||||
{
|
||||
name: "should reject missing_series_evals_to_resolve < 0",
|
||||
initialValue: util.Pointer(1),
|
||||
updatedValue: util.Pointer(-1),
|
||||
initialValue: util.Pointer[int64](1),
|
||||
updatedValue: util.Pointer[int64](-1),
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "should be able to reset missing_series_evals_to_resolve by setting it to 0",
|
||||
initialValue: util.Pointer(1),
|
||||
updatedValue: util.Pointer(0),
|
||||
initialValue: util.Pointer[int64](1),
|
||||
updatedValue: util.Pointer[int64](0),
|
||||
expectedValue: nil,
|
||||
expectedStatus: http.StatusAccepted,
|
||||
},
|
||||
|
@ -3474,7 +3474,7 @@ func TestIntegrationAlertRuleCRUD(t *testing.T) {
|
|||
},
|
||||
NoDataState: apimodels.NoDataState(ngmodels.Alerting),
|
||||
ExecErrState: apimodels.ExecutionErrorState(ngmodels.AlertingErrState),
|
||||
MissingSeriesEvalsToResolve: util.Pointer(2), // If UID is specified, this field is required
|
||||
MissingSeriesEvalsToResolve: util.Pointer[int64](2), // If UID is specified, this field is required
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue