Prometheus: Avoid parsing unused legacy datasource property (#87224)

* query cleanup

* parse query

* more comments
This commit is contained in:
Ryan McKinley 2024-05-05 15:00:53 +03:00 committed by GitHub
parent 8e96821c16
commit 333ed377d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 1 deletions

View File

@ -137,6 +137,8 @@ const (
var safeResolution = 11000 var safeResolution = 11000
// QueryModel includes both the common and specific values // 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 { type QueryModel struct {
PrometheusQueryProperties `json:",inline"` PrometheusQueryProperties `json:",inline"`
sdkapi.CommonQueryProperties `json:",inline"` sdkapi.CommonQueryProperties `json:",inline"`
@ -172,8 +174,22 @@ type Scope struct {
Matchers []*labels.Matcher 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) { 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 { if err := json.Unmarshal(query.JSON, model); err != nil {
return nil, err return nil, err
} }

View File

@ -436,6 +436,25 @@ func TestParse(t *testing.T) {
require.Equal(t, "rate(ALERTS{job=\"test\" [135000]}) + rate(ALERTS{job=\"test\" [2m15s]})", res.Expr) 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) { t.Run("parsing query model with ${__rate_interval_ms} and ${__rate_interval} variable", func(t *testing.T) {
timeRange := backend.TimeRange{ timeRange := backend.TimeRange{
From: now, From: now,