From 333ed377d6b936eb3c86ea7a81243258952de75f Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Sun, 5 May 2024 15:00:53 +0300 Subject: [PATCH] Prometheus: Avoid parsing unused legacy datasource property (#87224) * query cleanup * parse query * more comments --- pkg/promlib/models/query.go | 18 +++++++++++++++++- pkg/promlib/models/query_test.go | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/pkg/promlib/models/query.go b/pkg/promlib/models/query.go index 930de98ab0c..08fb240b9f1 100644 --- a/pkg/promlib/models/query.go +++ b/pkg/promlib/models/query.go @@ -137,6 +137,8 @@ const ( var safeResolution = 11000 // QueryModel includes both the common and specific values +// NOTE: this struct may have issues when decoding JSON that requires the special handling +// registered in https://github.com/grafana/grafana-plugin-sdk-go/blob/v0.228.0/experimental/apis/data/v0alpha1/query.go#L298 type QueryModel struct { PrometheusQueryProperties `json:",inline"` sdkapi.CommonQueryProperties `json:",inline"` @@ -172,8 +174,22 @@ type Scope struct { Matchers []*labels.Matcher } +// This internal query struct is just like QueryModel, except it does not include: +// sdkapi.CommonQueryProperties -- this avoids errors where the unused "datasource" property +// may be either a string or DataSourceRef +type internalQueryModel struct { + PrometheusQueryProperties `json:",inline"` + //sdkapi.CommonQueryProperties `json:",inline"` + IntervalMS float64 `json:"intervalMs,omitempty"` + + // The following properties may be part of the request payload, however they are not saved in panel JSON + // Timezone offset to align start & end time on backend + UtcOffsetSec int64 `json:"utcOffsetSec,omitempty"` + Interval string `json:"interval,omitempty"` +} + func Parse(span trace.Span, query backend.DataQuery, dsScrapeInterval string, intervalCalculator intervalv2.Calculator, fromAlert bool, enableScope bool) (*Query, error) { - model := &QueryModel{} + model := &internalQueryModel{} if err := json.Unmarshal(query.JSON, model); err != nil { return nil, err } diff --git a/pkg/promlib/models/query_test.go b/pkg/promlib/models/query_test.go index 21925581f53..8826e0c37c5 100644 --- a/pkg/promlib/models/query_test.go +++ b/pkg/promlib/models/query_test.go @@ -436,6 +436,25 @@ func TestParse(t *testing.T) { require.Equal(t, "rate(ALERTS{job=\"test\" [135000]}) + rate(ALERTS{job=\"test\" [2m15s]})", res.Expr) }) + t.Run("parsing query model with legacy datasource reference", func(t *testing.T) { + timeRange := backend.TimeRange{ + From: now, + To: now.Add(48 * time.Hour), + } + + // query with legacy datasource reference + q := queryContext(`{ + "datasource": "hello", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + }`, timeRange, 2*time.Minute) + + res, err := models.Parse(span, q, "15s", intervalCalculator, false, false) + require.NoError(t, err) + require.Equal(t, "A", res.RefId) + }) + t.Run("parsing query model with ${__rate_interval_ms} and ${__rate_interval} variable", func(t *testing.T) { timeRange := backend.TimeRange{ From: now,