From 1201170724db56ade4c237b9c4af33dcbe083f89 Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Thu, 10 Nov 2022 09:30:47 +0100 Subject: [PATCH] GoogleCloudMonitoring: Refactor query type definition (#58512) --- pkg/tsdb/cloudmonitoring/annotation_query.go | 10 +- pkg/tsdb/cloudmonitoring/cloudmonitoring.go | 103 ++++++++++-------- .../cloudmonitoring/cloudmonitoring_test.go | 46 +++++++- pkg/tsdb/cloudmonitoring/types.go | 1 + .../annotationSupport.test.ts | 6 +- .../cloud-monitoring/annotationSupport.ts | 3 +- .../datasource/cloud-monitoring/datasource.ts | 3 +- .../datasource/cloud-monitoring/types.ts | 2 +- 8 files changed, 107 insertions(+), 67 deletions(-) diff --git a/pkg/tsdb/cloudmonitoring/annotation_query.go b/pkg/tsdb/cloudmonitoring/annotation_query.go index 16ac1fc7352..6bfcec1f675 100644 --- a/pkg/tsdb/cloudmonitoring/annotation_query.go +++ b/pkg/tsdb/cloudmonitoring/annotation_query.go @@ -9,8 +9,6 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/data" - - "github.com/grafana/grafana/pkg/infra/log" ) type annotationEvent struct { @@ -20,15 +18,9 @@ type annotationEvent struct { Text string } -func (s *Service) executeAnnotationQuery(ctx context.Context, logger log.Logger, req *backend.QueryDataRequest, dsInfo datasourceInfo) ( +func (s *Service) executeAnnotationQuery(ctx context.Context, req *backend.QueryDataRequest, dsInfo datasourceInfo, queries []cloudMonitoringQueryExecutor) ( *backend.QueryDataResponse, error) { resp := backend.NewQueryDataResponse() - - queries, err := s.buildQueryExecutors(logger, req) - if err != nil { - return resp, err - } - queryRes, dr, _, err := queries[0].run(ctx, req, s, dsInfo, s.tracer) if err != nil { return resp, err diff --git a/pkg/tsdb/cloudmonitoring/cloudmonitoring.go b/pkg/tsdb/cloudmonitoring/cloudmonitoring.go index 511b461ca23..a690c78dc4e 100644 --- a/pkg/tsdb/cloudmonitoring/cloudmonitoring.go +++ b/pkg/tsdb/cloudmonitoring/cloudmonitoring.go @@ -59,6 +59,7 @@ var ( const ( gceAuthentication = "gce" jwtAuthentication = "jwt" + annotationQueryType = "annotation" metricQueryType = "metrics" sloQueryType = "slo" mqlEditorMode = "mql" @@ -137,10 +138,6 @@ type Service struct { gceDefaultProjectGetter func(ctx context.Context) (string, error) } -type QueryModel struct { - Type string `json:"type"` -} - type datasourceInfo struct { id int64 updated time.Time @@ -210,19 +207,54 @@ func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst } } +func migrateRequest(req *backend.QueryDataRequest) error { + for i, q := range req.Queries { + var rawQuery map[string]interface{} + err := json.Unmarshal(q.JSON, &rawQuery) + if err != nil { + return err + } + + if rawQuery["metricQuery"] == nil { + // migrate legacy query + var mq metricQuery + err = json.Unmarshal(q.JSON, &mq) + if err != nil { + return err + } + + b, err := json.Marshal(grafanaQuery{ + QueryType: metricQueryType, + MetricQuery: mq, + }) + if err != nil { + return err + } + q.JSON = b + } + + // Migrate type to queryType, which is only used for annotations + if rawQuery["type"] != nil && rawQuery["type"].(string) == "annotationQuery" { + q.QueryType = annotationQueryType + } + + req.Queries[i] = q + } + + return nil +} + // QueryData takes in the frontend queries, parses them into the CloudMonitoring query format // executes the queries against the CloudMonitoring API and parses the response into data frames func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { logger := slog.FromContext(ctx) - resp := backend.NewQueryDataResponse() if len(req.Queries) == 0 { - return resp, fmt.Errorf("query contains no queries") + return nil, fmt.Errorf("query contains no queries") } - model := &QueryModel{} - err := json.Unmarshal(req.Queries[0].JSON, model) + err := migrateRequest(req) if err != nil { - return resp, err + return nil, err } dsInfo, err := s.getDSInfo(req.PluginContext) @@ -230,27 +262,23 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) return nil, err } - switch model.Type { - case "annotationQuery": - resp, err = s.executeAnnotationQuery(ctx, logger, req, *dsInfo) - case "timeSeriesQuery": - fallthrough - default: - resp, err = s.executeTimeSeriesQuery(ctx, logger, req, *dsInfo) + queries, err := s.buildQueryExecutors(logger, req) + if err != nil { + return nil, err } - return resp, err + switch req.Queries[0].QueryType { + case annotationQueryType: + return s.executeAnnotationQuery(ctx, req, *dsInfo, queries) + default: + return s.executeTimeSeriesQuery(ctx, req, *dsInfo, queries) + } } -func (s *Service) executeTimeSeriesQuery(ctx context.Context, logger log.Logger, req *backend.QueryDataRequest, dsInfo datasourceInfo) ( +func (s *Service) executeTimeSeriesQuery(ctx context.Context, req *backend.QueryDataRequest, dsInfo datasourceInfo, queries []cloudMonitoringQueryExecutor) ( *backend.QueryDataResponse, error) { resp := backend.NewQueryDataResponse() - queryExecutors, err := s.buildQueryExecutors(logger, req) - if err != nil { - return resp, err - } - - for _, queryExecutor := range queryExecutors { + for _, queryExecutor := range queries { queryRes, dr, executedQueryString, err := queryExecutor.run(ctx, req, s, dsInfo, s.tracer) if err != nil { return resp, err @@ -267,32 +295,11 @@ func (s *Service) executeTimeSeriesQuery(ctx context.Context, logger log.Logger, } func queryModel(query backend.DataQuery) (grafanaQuery, error) { - var rawQuery map[string]interface{} - err := json.Unmarshal(query.JSON, &rawQuery) - if err != nil { - return grafanaQuery{}, err - } - - if rawQuery["metricQuery"] == nil { - // migrate legacy query - var mq metricQuery - err = json.Unmarshal(query.JSON, &mq) - if err != nil { - return grafanaQuery{}, err - } - - return grafanaQuery{ - QueryType: metricQueryType, - MetricQuery: mq, - }, nil - } - var q grafanaQuery - err = json.Unmarshal(query.JSON, &q) + err := json.Unmarshal(query.JSON, &q) if err != nil { return grafanaQuery{}, err } - return q, nil } @@ -321,7 +328,7 @@ func (s *Service) buildQueryExecutors(logger log.Logger, req *backend.QueryDataR logger: logger, } switch q.QueryType { - case metricQueryType: + case metricQueryType, annotationQueryType: if q.MetricQuery.EditorMode == mqlEditorMode { queryInterface = &cloudMonitoringTimeSeriesQuery{ RefID: query.RefID, @@ -354,7 +361,7 @@ func (s *Service) buildQueryExecutors(logger log.Logger, req *backend.QueryDataR setSloAggParams(¶ms, &q.SloQuery, durationSeconds, query.Interval.Milliseconds()) queryInterface = cmtsf default: - panic(fmt.Sprintf("Unrecognized query type %q", q.QueryType)) + return nil, fmt.Errorf("unrecognized query type %q", q.QueryType) } target = params.Encode() diff --git a/pkg/tsdb/cloudmonitoring/cloudmonitoring_test.go b/pkg/tsdb/cloudmonitoring/cloudmonitoring_test.go index 01351f445a2..ad01588cb56 100644 --- a/pkg/tsdb/cloudmonitoring/cloudmonitoring_test.go +++ b/pkg/tsdb/cloudmonitoring/cloudmonitoring_test.go @@ -52,7 +52,11 @@ func TestCloudMonitoring(t *testing.T) { t.Run("Parse migrated queries from frontend and build Google Cloud Monitoring API queries", func(t *testing.T) { t.Run("and query has no aggregation set", func(t *testing.T) { - qes, err := service.buildQueryExecutors(slog, baseReq()) + req := baseReq() + err := migrateRequest(req) + require.NoError(t, err) + require.NoError(t, err) + qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) queries := getCloudMonitoringQueriesFromInterface(t, qes) @@ -92,6 +96,8 @@ func TestCloudMonitoring(t *testing.T) { "metricType": "a/metric/type", "filters": ["key", "=", "value", "AND", "key2", "=", "value2", "AND", "resource.type", "=", "another/resource/type"] }`) + err := migrateRequest(query) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, query) require.NoError(t, err) @@ -124,6 +130,8 @@ func TestCloudMonitoring(t *testing.T) { "alignmentPeriod": "grafana-auto", "filters": ["key", "=", "value", "AND", "key2", "=", "value2"] }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -152,6 +160,8 @@ func TestCloudMonitoring(t *testing.T) { "alignmentPeriod": "grafana-auto", "filters": ["key", "=", "value", "AND", "key2", "=", "value2"] }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -186,6 +196,8 @@ func TestCloudMonitoring(t *testing.T) { "target": "target", "alignmentPeriod": "cloud-monitoring-auto" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -201,6 +213,8 @@ func TestCloudMonitoring(t *testing.T) { "target": "target", "alignmentPeriod": "cloud-monitoring-auto" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -216,6 +230,8 @@ func TestCloudMonitoring(t *testing.T) { "target": "target", "alignmentPeriod": "cloud-monitoring-auto" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -231,6 +247,8 @@ func TestCloudMonitoring(t *testing.T) { "target": "target", "alignmentPeriod": "cloud-monitoring-auto" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -250,6 +268,8 @@ func TestCloudMonitoring(t *testing.T) { "target": "target", "alignmentPeriod": "stackdriver-auto" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -280,6 +300,8 @@ func TestCloudMonitoring(t *testing.T) { "target": "target", "alignmentPeriod": "stackdriver-auto" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -310,6 +332,8 @@ func TestCloudMonitoring(t *testing.T) { "target": "target", "alignmentPeriod": "stackdriver-auto" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -340,6 +364,8 @@ func TestCloudMonitoring(t *testing.T) { "target": "target", "alignmentPeriod": "stackdriver-auto" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -370,6 +396,8 @@ func TestCloudMonitoring(t *testing.T) { req.Queries[0].JSON = json.RawMessage(`{ "alignmentPeriod": "+600s" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -400,6 +428,8 @@ func TestCloudMonitoring(t *testing.T) { "crossSeriesReducer": "REDUCE_SUM", "view": "FULL" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -444,6 +474,8 @@ func TestCloudMonitoring(t *testing.T) { "groupBys": ["metric.label.group1", "metric.label.group2"], "view": "FULL" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -738,6 +770,8 @@ func TestCloudMonitoring(t *testing.T) { "groupBys": ["labelname"], "view": "FULL" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -766,6 +800,8 @@ func TestCloudMonitoring(t *testing.T) { "view": "FULL", "preprocessor": "none" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -794,6 +830,8 @@ func TestCloudMonitoring(t *testing.T) { "view": "FULL", "preprocessor": "rate" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -820,6 +858,8 @@ func TestCloudMonitoring(t *testing.T) { "view": "FULL", "preprocessor": "rate" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -848,6 +888,8 @@ func TestCloudMonitoring(t *testing.T) { "view": "FULL", "preprocessor": "delta" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) @@ -874,6 +916,8 @@ func TestCloudMonitoring(t *testing.T) { "view": "FULL", "preprocessor": "delta" }`) + err := migrateRequest(req) + require.NoError(t, err) qes, err := service.buildQueryExecutors(slog, req) require.NoError(t, err) diff --git a/pkg/tsdb/cloudmonitoring/types.go b/pkg/tsdb/cloudmonitoring/types.go index 02afc94d630..1f939b73b88 100644 --- a/pkg/tsdb/cloudmonitoring/types.go +++ b/pkg/tsdb/cloudmonitoring/types.go @@ -80,6 +80,7 @@ type ( QueryType string MetricQuery metricQuery SloQuery sloQuery + Type string } cloudMonitoringBucketOptions struct { diff --git a/public/app/plugins/datasource/cloud-monitoring/annotationSupport.test.ts b/public/app/plugins/datasource/cloud-monitoring/annotationSupport.test.ts index dbdcb196a7e..f4489bb5bbd 100644 --- a/public/app/plugins/datasource/cloud-monitoring/annotationSupport.test.ts +++ b/public/app/plugins/datasource/cloud-monitoring/annotationSupport.test.ts @@ -13,8 +13,7 @@ import { const query: CloudMonitoringQuery = { refId: 'query', - queryType: QueryType.METRICS, - type: 'annotationQuery', + queryType: QueryType.ANNOTATION, intervalMs: 0, metricQuery: { editorMode: EditorMode.Visual, @@ -84,9 +83,8 @@ describe('CloudMonitoringAnnotationSupport', () => { text: 'text', title: 'title', }, - queryType: 'metrics', + queryType: 'annotation', refId: 'annotationQuery', - type: 'annotationQuery', }, }; expect(annotationSupport.prepareAnnotation?.(legacyAnnotationQuery)).toEqual(expectedQuery); diff --git a/public/app/plugins/datasource/cloud-monitoring/annotationSupport.ts b/public/app/plugins/datasource/cloud-monitoring/annotationSupport.ts index 04f69d59054..ba237c16193 100644 --- a/public/app/plugins/datasource/cloud-monitoring/annotationSupport.ts +++ b/public/app/plugins/datasource/cloud-monitoring/annotationSupport.ts @@ -41,8 +41,7 @@ export const CloudMonitoringAnnotationSupport: ( target: { intervalMs: ds.intervalMs, refId: target?.refId || 'annotationQuery', - type: 'annotationQuery', - queryType: QueryType.METRICS, + queryType: QueryType.ANNOTATION, metricQuery: { projectName: target?.projectName || ds.getDefaultProject(), editorMode: EditorMode.Visual, diff --git a/public/app/plugins/datasource/cloud-monitoring/datasource.ts b/public/app/plugins/datasource/cloud-monitoring/datasource.ts index 3893e1345bc..4a1f5f542d5 100644 --- a/public/app/plugins/datasource/cloud-monitoring/datasource.ts +++ b/public/app/plugins/datasource/cloud-monitoring/datasource.ts @@ -198,9 +198,8 @@ export default class CloudMonitoringDatasource extends DataSourceWithBackend< return { refId, intervalMs, - type, hide, - queryType: QueryType.METRICS, + queryType: type === 'annotationQuery' ? QueryType.ANNOTATION : QueryType.METRICS, metricQuery: { ...rest, view: rest.view || 'FULL', diff --git a/public/app/plugins/datasource/cloud-monitoring/types.ts b/public/app/plugins/datasource/cloud-monitoring/types.ts index bba62325c17..f8b1d1b01d9 100644 --- a/public/app/plugins/datasource/cloud-monitoring/types.ts +++ b/public/app/plugins/datasource/cloud-monitoring/types.ts @@ -57,6 +57,7 @@ export interface Aggregation { export enum QueryType { METRICS = 'metrics', SLO = 'slo', + ANNOTATION = 'annotation', } export enum EditorMode { @@ -152,7 +153,6 @@ export interface CloudMonitoringQuery extends DataQuery { metricQuery: MetricQuery | AnnotationMetricQuery; sloQuery?: SLOQuery; intervalMs: number; - type: string; } export interface CloudMonitoringOptions extends DataSourceJsonData {