From 32869c96df5510d60ebd1d829341fe25bbe89144 Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Thu, 20 Apr 2023 14:56:53 +0100 Subject: [PATCH] [v9.5.x] Alerting: Fix DatasourceUID and RefID missing for DatasourceNoData alerts (#66962) Alerting: Fix DatasourceUID and RefID missing for DatasourceNoData alerts (#66733) This commit fixes a bug where DatasourceUID and RefID annotations are missing for DatasourceNoData alerts in Grafana 9.5. This bug affects datasource plugins that have moved to using the data plane contract. (cherry picked from commit 35342a3c76f483826e03b6f3bf89d9fef4983a2f) Co-authored-by: George Robinson --- pkg/services/ngalert/eval/eval.go | 23 ++++++++++++++++++----- pkg/services/ngalert/eval/eval_test.go | 20 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/pkg/services/ngalert/eval/eval.go b/pkg/services/ngalert/eval/eval.go index 8311dea2bee..3a0f2313158 100644 --- a/pkg/services/ngalert/eval/eval.go +++ b/pkg/services/ngalert/eval/eval.go @@ -321,14 +321,27 @@ func queryDataResponseToExecutionResults(c models.Condition, execResp *backend.Q result := ExecutionResults{Results: make(map[string]data.Frames)} for refID, res := range execResp.Responses { - if len(res.Frames) == 0 { - // to ensure that NoData is consistent with Results we do not initialize NoData - // unless there is at least one RefID that returned no data + // There are two possible frame formats for No Data: + // + // 1. A response with no frames + // 2. A response with 1 frame but no fields + // + // The first format is not documented in the data plane contract but needs to be + // supported for older datasource plugins. The second format is documented in + // https://github.com/grafana/grafana-plugin-sdk-go/blob/main/data/contract_docs/contract.md + // and is what datasource plugins should use going forward. + if len(res.Frames) <= 1 { + // To make sure NoData is nil when Results are also nil we wait to initialize + // NoData until there is at least one query or expression that returned no data if result.NoData == nil { result.NoData = make(map[string]string) } - if s, ok := datasourceUIDsForRefIDs[refID]; ok && s != datasourceExprUID { - result.NoData[refID] = s + hasNoFrames := len(res.Frames) == 0 + hasNoFields := len(res.Frames) == 1 && len(res.Frames[0].Fields) == 0 + if hasNoFrames || hasNoFields { + if s, ok := datasourceUIDsForRefIDs[refID]; ok && s != datasourceExprUID { + result.NoData[refID] = s + } } } diff --git a/pkg/services/ngalert/eval/eval_test.go b/pkg/services/ngalert/eval/eval_test.go index 3d01bbbdd11..ba40dc32145 100644 --- a/pkg/services/ngalert/eval/eval_test.go +++ b/pkg/services/ngalert/eval/eval_test.go @@ -573,6 +573,26 @@ func TestEvaluate(t *testing.T) { "ref_id": "A", }, }}, + }, { + name: "is no data for one frame with no fields", + cond: models.Condition{ + Data: []models.AlertQuery{{ + RefID: "A", + DatasourceUID: "test", + }}, + }, + resp: backend.QueryDataResponse{ + Responses: backend.Responses{ + "A": {Frames: []*data.Frame{{Fields: nil}}}, + }, + }, + expected: Results{{ + State: NoData, + Instance: data.Labels{ + "datasource_uid": "test", + "ref_id": "A", + }, + }}, }} for _, tc := range cases {