From 35342a3c76f483826e03b6f3bf89d9fef4983a2f Mon Sep 17 00:00:00 2001 From: George Robinson Date: Thu, 20 Apr 2023 14:38:20 +0100 Subject: [PATCH] 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. --- 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 3d1eb8cb620..5708bfe927e 100644 --- a/pkg/services/ngalert/eval/eval_test.go +++ b/pkg/services/ngalert/eval/eval_test.go @@ -575,6 +575,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 {