From e12c571abf488123313290f484c02d2457713e73 Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Wed, 4 Jan 2023 15:57:34 +0100 Subject: [PATCH] [v9.3.x] Alerting: Fix conversion of alert state from db state during manager warmup (#60976) Alerting: Fix conversion of alert state from db state during manager warmup (#60933) (cherry picked from commit 4d989860fb2b4adf327ae5720819806731f7492d) Co-authored-by: Yuri Tseretyan --- pkg/services/ngalert/state/manager.go | 13 +++- pkg/services/ngalert/state/manager_test.go | 91 +++++++++++++++++++++- 2 files changed, 97 insertions(+), 7 deletions(-) diff --git a/pkg/services/ngalert/state/manager.go b/pkg/services/ngalert/state/manager.go index 388adb81403..6657111109a 100644 --- a/pkg/services/ngalert/state/manager.go +++ b/pkg/services/ngalert/state/manager.go @@ -359,13 +359,18 @@ func (st *Manager) deleteAlertStates(ctx context.Context, logger log.Logger, sta } } -// TODO: why wouldn't you allow other types like NoData or Error? func translateInstanceState(state ngModels.InstanceStateType) eval.State { - switch { - case state == ngModels.InstanceStateFiring: + switch state { + case ngModels.InstanceStateFiring: return eval.Alerting - case state == ngModels.InstanceStateNormal: + case ngModels.InstanceStateNormal: return eval.Normal + case ngModels.InstanceStateError: + return eval.Error + case ngModels.InstanceStateNoData: + return eval.NoData + case ngModels.InstanceStatePending: + return eval.Pending default: return eval.Error } diff --git a/pkg/services/ngalert/state/manager_test.go b/pkg/services/ngalert/state/manager_test.go index 06974b44089..4b2d87cb438 100644 --- a/pkg/services/ngalert/state/manager_test.go +++ b/pkg/services/ngalert/state/manager_test.go @@ -68,6 +68,48 @@ func TestWarmStateCache(t *testing.T) { LastEvaluationTime: evaluationTime, Annotations: map[string]string{"testAnnoKey": "testAnnoValue"}, }, + { + AlertRuleUID: rule.UID, + OrgID: rule.OrgID, + CacheID: `[["test3","testValue3"]]`, + Labels: data.Labels{"test3": "testValue3"}, + State: eval.NoData, + Results: []state.Evaluation{ + {EvaluationTime: evaluationTime, EvaluationState: eval.NoData}, + }, + StartsAt: evaluationTime.Add(-1 * time.Minute), + EndsAt: evaluationTime.Add(1 * time.Minute), + LastEvaluationTime: evaluationTime, + Annotations: map[string]string{"testAnnoKey": "testAnnoValue"}, + }, + { + AlertRuleUID: rule.UID, + OrgID: rule.OrgID, + CacheID: `[["test4","testValue4"]]`, + Labels: data.Labels{"test4": "testValue4"}, + State: eval.Error, + Results: []state.Evaluation{ + {EvaluationTime: evaluationTime, EvaluationState: eval.Error}, + }, + StartsAt: evaluationTime.Add(-1 * time.Minute), + EndsAt: evaluationTime.Add(1 * time.Minute), + LastEvaluationTime: evaluationTime, + Annotations: map[string]string{"testAnnoKey": "testAnnoValue"}, + }, + { + AlertRuleUID: rule.UID, + OrgID: rule.OrgID, + CacheID: `[["test5","testValue5"]]`, + Labels: data.Labels{"test5": "testValue5"}, + State: eval.Pending, + Results: []state.Evaluation{ + {EvaluationTime: evaluationTime, EvaluationState: eval.Pending}, + }, + StartsAt: evaluationTime.Add(-1 * time.Minute), + EndsAt: evaluationTime.Add(1 * time.Minute), + LastEvaluationTime: evaluationTime, + Annotations: map[string]string{"testAnnoKey": "testAnnoValue"}, + }, } labels := models.InstanceLabels{"test1": "testValue1"} @@ -85,8 +127,6 @@ func TestWarmStateCache(t *testing.T) { Labels: labels, } - _ = dbstore.SaveAlertInstances(ctx, instance1) - labels = models.InstanceLabels{"test2": "testValue2"} _, hash, _ = labels.StringAndHash() instance2 := models.AlertInstance{ @@ -101,7 +141,52 @@ func TestWarmStateCache(t *testing.T) { CurrentStateEnd: evaluationTime.Add(1 * time.Minute), Labels: labels, } - _ = dbstore.SaveAlertInstances(ctx, instance2) + + labels = models.InstanceLabels{"test3": "testValue3"} + _, hash, _ = labels.StringAndHash() + instance3 := models.AlertInstance{ + AlertInstanceKey: models.AlertInstanceKey{ + RuleOrgID: rule.OrgID, + RuleUID: rule.UID, + LabelsHash: hash, + }, + CurrentState: models.InstanceStateNoData, + LastEvalTime: evaluationTime, + CurrentStateSince: evaluationTime.Add(-1 * time.Minute), + CurrentStateEnd: evaluationTime.Add(1 * time.Minute), + Labels: labels, + } + + labels = models.InstanceLabels{"test4": "testValue4"} + _, hash, _ = labels.StringAndHash() + instance4 := models.AlertInstance{ + AlertInstanceKey: models.AlertInstanceKey{ + RuleOrgID: rule.OrgID, + RuleUID: rule.UID, + LabelsHash: hash, + }, + CurrentState: models.InstanceStateError, + LastEvalTime: evaluationTime, + CurrentStateSince: evaluationTime.Add(-1 * time.Minute), + CurrentStateEnd: evaluationTime.Add(1 * time.Minute), + Labels: labels, + } + + labels = models.InstanceLabels{"test5": "testValue5"} + _, hash, _ = labels.StringAndHash() + instance5 := models.AlertInstance{ + AlertInstanceKey: models.AlertInstanceKey{ + RuleOrgID: rule.OrgID, + RuleUID: rule.UID, + LabelsHash: hash, + }, + CurrentState: models.InstanceStatePending, + LastEvalTime: evaluationTime, + CurrentStateSince: evaluationTime.Add(-1 * time.Minute), + CurrentStateEnd: evaluationTime.Add(1 * time.Minute), + Labels: labels, + } + _ = dbstore.SaveAlertInstances(ctx, instance1, instance2, instance3, instance4, instance5) st := state.NewManager(testMetrics.GetStateMetrics(), nil, dbstore, &state.NoopImageService{}, clock.NewMock(), &state.FakeHistorian{}) st.Warm(ctx, dbstore)