Introduce TSDB service (#31520)

* Introduce TSDB service

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

Co-authored-by: Erik Sundell <erik.sundell87@gmail.com>
Co-authored-by: Will Browne <will.browne@grafana.com>
Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
This commit is contained in:
Arve Knudsen
2021-03-08 07:02:49 +01:00
committed by GitHub
co-authored by Erik Sundell Will Browne Torkel Ödegaard Will Browne Zoltán Bedi
parent c899bf3592
commit b79e61656a
203 changed files with 5269 additions and 4776 deletions
+22 -20
View File
@@ -8,16 +8,17 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/util/errutil"
)
func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
result := &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult),
func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryContext plugins.DataQuery) (
plugins.DataResponse, error) {
result := plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
}
firstQuery := queryContext.Queries[0]
queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: firstQuery.RefId}
queryResult := plugins.DataQueryResult{Meta: simplejson.New(), RefID: firstQuery.RefID}
parameters := firstQuery.Model
usePrefixMatch := parameters.Get("prefixMatching").MustBool(false)
@@ -27,7 +28,7 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo
dimensions := parameters.Get("dimensions").MustMap()
statistics, err := parseStatistics(parameters)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
period := int64(parameters.Get("period").MustInt(0))
if period == 0 && !usePrefixMatch {
@@ -38,7 +39,7 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo
cli, err := e.getCWClient(region)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
var alarmNames []*string
@@ -50,7 +51,7 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo
}
resp, err := cli.DescribeAlarms(params)
if err != nil {
return nil, errutil.Wrap("failed to call cloudwatch:DescribeAlarms", err)
return plugins.DataResponse{}, errutil.Wrap("failed to call cloudwatch:DescribeAlarms", err)
}
alarmNames = filterAlarms(resp, namespace, metricName, dimensions, statistics, period)
} else {
@@ -81,7 +82,7 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo
}
resp, err := cli.DescribeAlarmsForMetric(params)
if err != nil {
return nil, errutil.Wrap("failed to call cloudwatch:DescribeAlarmsForMetric", err)
return plugins.DataResponse{}, errutil.Wrap("failed to call cloudwatch:DescribeAlarmsForMetric", err)
}
for _, alarm := range resp.MetricAlarms {
alarmNames = append(alarmNames, alarm.AlarmName)
@@ -91,11 +92,11 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo
startTime, err := queryContext.TimeRange.ParseFrom()
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
endTime, err := queryContext.TimeRange.ParseTo()
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
annotations := make([]map[string]string, 0)
@@ -108,7 +109,7 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo
}
resp, err := cli.DescribeAlarmHistory(params)
if err != nil {
return nil, errutil.Wrap("failed to call cloudwatch:DescribeAlarmHistory", err)
return plugins.DataResponse{}, errutil.Wrap("failed to call cloudwatch:DescribeAlarmHistory", err)
}
for _, history := range resp.AlarmHistoryItems {
annotation := make(map[string]string)
@@ -120,15 +121,15 @@ func (e *cloudWatchExecutor) executeAnnotationQuery(ctx context.Context, queryCo
}
}
transformAnnotationToTable(annotations, queryResult)
result.Results[firstQuery.RefId] = queryResult
return result, err
transformAnnotationToTable(annotations, &queryResult)
result.Results[firstQuery.RefID] = queryResult
return result, nil
}
func transformAnnotationToTable(data []map[string]string, result *tsdb.QueryResult) {
table := &tsdb.Table{
Columns: make([]tsdb.TableColumn, 4),
Rows: make([]tsdb.RowValues, 0),
func transformAnnotationToTable(data []map[string]string, result *plugins.DataQueryResult) {
table := plugins.DataTable{
Columns: make([]plugins.DataTableColumn, 4),
Rows: make([]plugins.DataRowValues, 0),
}
table.Columns[0].Text = "time"
table.Columns[1].Text = "title"
@@ -147,7 +148,8 @@ func transformAnnotationToTable(data []map[string]string, result *tsdb.QueryResu
result.Meta.Set("rowCount", len(data))
}
func filterAlarms(alarms *cloudwatch.DescribeAlarmsOutput, namespace string, metricName string, dimensions map[string]interface{}, statistics []string, period int64) []*string {
func filterAlarms(alarms *cloudwatch.DescribeAlarmsOutput, namespace string, metricName string,
dimensions map[string]interface{}, statistics []string, period int64) []*string {
alarmNames := make([]*string, 0)
for _, alarm := range alarms.MetricAlarms {
+33 -32
View File
@@ -26,9 +26,9 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb"
)
type datasourceInfo struct {
@@ -67,15 +67,13 @@ type CloudWatchService struct {
}
func (s *CloudWatchService) Init() error {
plog.Debug("initing")
tsdb.RegisterTsdbQueryEndpoint("cloudwatch", func(ds *models.DataSource) (tsdb.TsdbQueryEndpoint, error) {
return newExecutor(s.LogsService), nil
})
return nil
}
func (s *CloudWatchService) NewExecutor(*models.DataSource) (plugins.DataPlugin, error) {
return newExecutor(s.LogsService), nil
}
func newExecutor(logsService *LogsService) *cloudWatchExecutor {
return &cloudWatchExecutor{
logsService: logsService,
@@ -248,12 +246,12 @@ func (e *cloudWatchExecutor) getRGTAClient(region string) (resourcegroupstagging
}
func (e *cloudWatchExecutor) alertQuery(ctx context.Context, logsClient cloudwatchlogsiface.CloudWatchLogsAPI,
queryContext *tsdb.TsdbQuery) (*cloudwatchlogs.GetQueryResultsOutput, error) {
queryContext plugins.DataQuery) (*cloudwatchlogs.GetQueryResultsOutput, error) {
const maxAttempts = 8
const pollPeriod = 1000 * time.Millisecond
queryParams := queryContext.Queries[0].Model
startQueryOutput, err := e.executeStartQuery(ctx, logsClient, queryParams, queryContext.TimeRange)
startQueryOutput, err := e.executeStartQuery(ctx, logsClient, queryParams, *queryContext.TimeRange)
if err != nil {
return nil, err
}
@@ -285,15 +283,17 @@ func (e *cloudWatchExecutor) alertQuery(ctx context.Context, logsClient cloudwat
return nil, nil
}
// Query executes a CloudWatch query.
func (e *cloudWatchExecutor) Query(ctx context.Context, dsInfo *models.DataSource, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
// DataQuery executes a CloudWatch query.
func (e *cloudWatchExecutor) DataQuery(ctx context.Context, dsInfo *models.DataSource,
queryContext plugins.DataQuery) (plugins.DataResponse, error) {
e.DataSource = dsInfo
/*
Unlike many other data sources, with Cloudwatch Logs query requests don't receive the results as the response to the query, but rather
an ID is first returned. Following this, a client is expected to send requests along with the ID until the status of the query is complete,
receiving (possibly partial) results each time. For queries made via dashboards and Explore, the logic of making these repeated queries is handled on
the frontend, but because alerts are executed on the backend the logic needs to be reimplemented here.
Unlike many other data sources, with Cloudwatch Logs query requests don't receive the results as the response
to the query, but rather an ID is first returned. Following this, a client is expected to send requests along
with the ID until the status of the query is complete, receiving (possibly partial) results each time. For
queries made via dashboards and Explore, the logic of making these repeated queries is handled on the
frontend, but because alerts are executed on the backend the logic needs to be reimplemented here.
*/
queryParams := queryContext.Queries[0].Model
_, fromAlert := queryContext.Headers["FromAlert"]
@@ -306,7 +306,7 @@ func (e *cloudWatchExecutor) Query(ctx context.Context, dsInfo *models.DataSourc
queryType := queryParams.Get("type").MustString("")
var err error
var result *tsdb.Response
var result plugins.DataResponse
switch queryType {
case "metricFindQuery":
result, err = e.executeMetricFindQuery(ctx, queryContext)
@@ -325,7 +325,8 @@ func (e *cloudWatchExecutor) Query(ctx context.Context, dsInfo *models.DataSourc
return result, err
}
func (e *cloudWatchExecutor) executeLogAlertQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
func (e *cloudWatchExecutor) executeLogAlertQuery(ctx context.Context, queryContext plugins.DataQuery) (
plugins.DataResponse, error) {
queryParams := queryContext.Queries[0].Model
queryParams.Set("subtype", "StartQuery")
queryParams.Set("queryString", queryParams.Get("expression").MustString(""))
@@ -338,12 +339,12 @@ func (e *cloudWatchExecutor) executeLogAlertQuery(ctx context.Context, queryCont
logsClient, err := e.getCWLogsClient(region)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
result, err := e.executeStartQuery(ctx, logsClient, queryParams, queryContext.TimeRange)
result, err := e.executeStartQuery(ctx, logsClient, queryParams, *queryContext.TimeRange)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
queryParams.Set("queryId", *result.QueryId)
@@ -351,38 +352,38 @@ func (e *cloudWatchExecutor) executeLogAlertQuery(ctx context.Context, queryCont
// Get query results
getQueryResultsOutput, err := e.alertQuery(ctx, logsClient, queryContext)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
dataframe, err := logsResultsToDataframes(getQueryResultsOutput)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
statsGroups := queryParams.Get("statsGroups").MustStringArray()
if len(statsGroups) > 0 && len(dataframe.Fields) > 0 {
groupedFrames, err := groupResults(dataframe, statsGroups)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
response := &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult),
response := plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
}
response.Results["A"] = &tsdb.QueryResult{
RefId: "A",
Dataframes: tsdb.NewDecodedDataFrames(groupedFrames),
response.Results["A"] = plugins.DataQueryResult{
RefID: "A",
Dataframes: plugins.NewDecodedDataFrames(groupedFrames),
}
return response, nil
}
response := &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
response := plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"A": {
RefId: "A",
Dataframes: tsdb.NewDecodedDataFrames(data.Frames{dataframe}),
RefID: "A",
Dataframes: plugins.NewDecodedDataFrames(data.Frames{dataframe}),
},
},
}
+22 -18
View File
@@ -18,8 +18,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/util/retryer"
"golang.org/x/sync/errgroup"
)
@@ -108,20 +108,21 @@ func (r *logQueryRunner) publishResults(channelName string) error {
// executeLiveLogQuery executes a CloudWatch Logs query with live updates over WebSocket.
// A WebSocket channel is created, which goroutines send responses over.
func (e *cloudWatchExecutor) executeLiveLogQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
func (e *cloudWatchExecutor) executeLiveLogQuery(ctx context.Context, queryContext plugins.DataQuery) (
plugins.DataResponse, error) {
responseChannelName := uuid.New().String()
responseChannel := make(chan *tsdb.Response)
responseChannel := make(chan plugins.DataResponse)
if err := e.logsService.AddResponseChannel("plugin/cloudwatch/"+responseChannelName, responseChannel); err != nil {
close(responseChannel)
return nil, err
return plugins.DataResponse{}, err
}
go e.sendLiveQueriesToChannel(queryContext, responseChannel)
response := &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
response := plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"A": {
RefId: "A",
RefID: "A",
Meta: simplejson.NewFromAny(map[string]interface{}{
"channelName": responseChannelName,
}),
@@ -132,7 +133,8 @@ func (e *cloudWatchExecutor) executeLiveLogQuery(ctx context.Context, queryConte
return response, nil
}
func (e *cloudWatchExecutor) sendLiveQueriesToChannel(queryContext *tsdb.TsdbQuery, responseChannel chan *tsdb.Response) {
func (e *cloudWatchExecutor) sendLiveQueriesToChannel(queryContext plugins.DataQuery,
responseChannel chan plugins.DataResponse) {
defer close(responseChannel)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
@@ -142,7 +144,7 @@ func (e *cloudWatchExecutor) sendLiveQueriesToChannel(queryContext *tsdb.TsdbQue
for _, query := range queryContext.Queries {
query := query
eg.Go(func() error {
return e.startLiveQuery(ectx, responseChannel, query, queryContext.TimeRange)
return e.startLiveQuery(ectx, responseChannel, query, *queryContext.TimeRange)
})
}
@@ -200,7 +202,8 @@ func (e *cloudWatchExecutor) fetchConcurrentQueriesQuota(region string) int {
return defaultConcurrentQueries
}
if defaultConcurrentQueriesQuota != nil && defaultConcurrentQueriesQuota.Quota != nil && defaultConcurrentQueriesQuota.Quota.Value != nil {
if defaultConcurrentQueriesQuota != nil && defaultConcurrentQueriesQuota.Quota != nil &&
defaultConcurrentQueriesQuota.Quota.Value != nil {
return int(*defaultConcurrentQueriesQuota.Quota.Value)
}
@@ -208,7 +211,8 @@ func (e *cloudWatchExecutor) fetchConcurrentQueriesQuota(region string) int {
return defaultConcurrentQueries
}
func (e *cloudWatchExecutor) startLiveQuery(ctx context.Context, responseChannel chan *tsdb.Response, query *tsdb.Query, timeRange *tsdb.TimeRange) error {
func (e *cloudWatchExecutor) startLiveQuery(ctx context.Context, responseChannel chan plugins.DataResponse,
query plugins.DataSubQuery, timeRange plugins.DataTimeRange) error {
defaultRegion := e.DataSource.JsonData.Get("defaultRegion").MustString()
parameters := query.Model
region := parameters.Get("region").MustString(defaultRegion)
@@ -250,8 +254,8 @@ func (e *cloudWatchExecutor) startLiveQuery(ctx context.Context, responseChannel
return retryer.FuncError, err
}
dataFrame.Name = query.RefId
dataFrame.RefID = query.RefId
dataFrame.Name = query.RefID
dataFrame.RefID = query.RefID
var dataFrames data.Frames
// When a query of the form "stats ... by ..." is made, we want to return
@@ -281,11 +285,11 @@ func (e *cloudWatchExecutor) startLiveQuery(ctx context.Context, responseChannel
dataFrames = data.Frames{dataFrame}
}
responseChannel <- &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
query.RefId: {
RefId: query.RefId,
Dataframes: tsdb.NewDecodedDataFrames(dataFrames),
responseChannel <- plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
query.RefID: {
RefID: query.RefID,
Dataframes: plugins.NewDecodedDataFrames(dataFrames),
},
},
}
+24 -18
View File
@@ -12,12 +12,13 @@ import (
"github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"golang.org/x/sync/errgroup"
)
func (e *cloudWatchExecutor) executeLogActions(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
resultChan := make(chan *tsdb.QueryResult, len(queryContext.Queries))
func (e *cloudWatchExecutor) executeLogActions(ctx context.Context,
queryContext plugins.DataQuery) (plugins.DataResponse, error) {
resultChan := make(chan plugins.DataQueryResult, len(queryContext.Queries))
eg, ectx := errgroup.WithContext(ctx)
for _, query := range queryContext.Queries {
@@ -42,7 +43,10 @@ func (e *cloudWatchExecutor) executeLogActions(ctx context.Context, queryContext
return err
}
resultChan <- &tsdb.QueryResult{RefId: query.RefId, Dataframes: tsdb.NewDecodedDataFrames(groupedFrames)}
resultChan <- plugins.DataQueryResult{
RefID: query.RefID,
Dataframes: plugins.NewDecodedDataFrames(groupedFrames),
}
return nil
}
@@ -54,30 +58,31 @@ func (e *cloudWatchExecutor) executeLogActions(ctx context.Context, queryContext
}
}
resultChan <- &tsdb.QueryResult{
RefId: query.RefId,
Dataframes: tsdb.NewDecodedDataFrames(data.Frames{dataframe}),
resultChan <- plugins.DataQueryResult{
RefID: query.RefID,
Dataframes: plugins.NewDecodedDataFrames(data.Frames{dataframe}),
}
return nil
})
}
if err := eg.Wait(); err != nil {
return nil, err
return plugins.DataResponse{}, err
}
close(resultChan)
response := &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult),
response := plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
}
for result := range resultChan {
response.Results[result.RefId] = result
response.Results[result.RefID] = result
}
return response, nil
}
func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, queryContext *tsdb.TsdbQuery, query *tsdb.Query) (*data.Frame, error) {
func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, queryContext plugins.DataQuery,
query plugins.DataSubQuery) (*data.Frame, error) {
parameters := query.Model
subType := query.Model.Get("subtype").MustString()
@@ -94,13 +99,13 @@ func (e *cloudWatchExecutor) executeLogAction(ctx context.Context, queryContext
case "DescribeLogGroups":
data, err = e.handleDescribeLogGroups(ctx, logsClient, parameters)
case "GetLogGroupFields":
data, err = e.handleGetLogGroupFields(ctx, logsClient, parameters, query.RefId)
data, err = e.handleGetLogGroupFields(ctx, logsClient, parameters, query.RefID)
case "StartQuery":
data, err = e.handleStartQuery(ctx, logsClient, parameters, queryContext.TimeRange, query.RefId)
data, err = e.handleStartQuery(ctx, logsClient, parameters, *queryContext.TimeRange, query.RefID)
case "StopQuery":
data, err = e.handleStopQuery(ctx, logsClient, parameters)
case "GetQueryResults":
data, err = e.handleGetQueryResults(ctx, logsClient, parameters, query.RefId)
data, err = e.handleGetQueryResults(ctx, logsClient, parameters, query.RefID)
case "GetLogEvents":
data, err = e.handleGetLogEvents(ctx, logsClient, parameters)
}
@@ -195,7 +200,7 @@ func (e *cloudWatchExecutor) handleDescribeLogGroups(ctx context.Context,
}
func (e *cloudWatchExecutor) executeStartQuery(ctx context.Context, logsClient cloudwatchlogsiface.CloudWatchLogsAPI,
parameters *simplejson.Json, timeRange *tsdb.TimeRange) (*cloudwatchlogs.StartQueryOutput, error) {
parameters *simplejson.Json, timeRange plugins.DataTimeRange) (*cloudwatchlogs.StartQueryOutput, error) {
startTime, err := timeRange.ParseFrom()
if err != nil {
return nil, err
@@ -214,7 +219,8 @@ func (e *cloudWatchExecutor) executeStartQuery(ctx context.Context, logsClient c
// so that a row's context can be retrieved later if necessary.
// The usage of ltrim around the @log/@logStream fields is a necessary workaround, as without it,
// CloudWatch wouldn't consider a query using a non-alised @log/@logStream valid.
modifiedQueryString := "fields @timestamp,ltrim(@log) as " + logIdentifierInternal + ",ltrim(@logStream) as " + logStreamIdentifierInternal + "|" + parameters.Get("queryString").MustString("")
modifiedQueryString := "fields @timestamp,ltrim(@log) as " + logIdentifierInternal + ",ltrim(@logStream) as " +
logStreamIdentifierInternal + "|" + parameters.Get("queryString").MustString("")
startQueryInput := &cloudwatchlogs.StartQueryInput{
StartTime: aws.Int64(startTime.Unix()),
@@ -231,7 +237,7 @@ func (e *cloudWatchExecutor) executeStartQuery(ctx context.Context, logsClient c
}
func (e *cloudWatchExecutor) handleStartQuery(ctx context.Context, logsClient cloudwatchlogsiface.CloudWatchLogsAPI,
parameters *simplejson.Json, timeRange *tsdb.TimeRange, refID string) (*data.Frame, error) {
parameters *simplejson.Json, timeRange plugins.DataTimeRange, refID string) (*data.Frame, error) {
startQueryResponse, err := e.executeStartQuery(ctx, logsClient, parameters, timeRange)
if err != nil {
return nil, err
+45 -45
View File
@@ -12,7 +12,7 @@ import (
"github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -48,8 +48,8 @@ func TestQuery_DescribeLogGroups(t *testing.T) {
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "logAction",
@@ -62,10 +62,10 @@ func TestQuery_DescribeLogGroups(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Dataframes: tsdb.NewDecodedDataFrames(data.Frames{
Dataframes: plugins.NewDecodedDataFrames(data.Frames{
&data.Frame{
Name: "logGroups",
Fields: []*data.Field{
@@ -101,8 +101,8 @@ func TestQuery_DescribeLogGroups(t *testing.T) {
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "logAction",
@@ -115,10 +115,10 @@ func TestQuery_DescribeLogGroups(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Dataframes: tsdb.NewDecodedDataFrames(data.Frames{
Dataframes: plugins.NewDecodedDataFrames(data.Frames{
&data.Frame{
Name: "logGroups",
Fields: []*data.Field{
@@ -171,10 +171,10 @@ func TestQuery_GetLogGroupFields(t *testing.T) {
const refID = "A"
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
RefId: refID,
RefID: refID,
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "logAction",
"subtype": "GetLogGroupFields",
@@ -202,11 +202,11 @@ func TestQuery_GetLogGroupFields(t *testing.T) {
},
}
expFrame.RefID = refID
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
refID: {
Dataframes: tsdb.NewDecodedDataFrames(data.Frames{expFrame}),
RefId: refID,
Dataframes: plugins.NewDecodedDataFrames(data.Frames{expFrame}),
RefID: refID,
},
},
}, resp)
@@ -244,15 +244,15 @@ func TestQuery_StartQuery(t *testing.T) {
},
}
timeRange := &tsdb.TimeRange{
timeRange := plugins.DataTimeRange{
From: "1584873443000",
To: "1584700643000",
}
executor := newExecutor(nil)
_, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
TimeRange: timeRange,
Queries: []*tsdb.Query{
_, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
TimeRange: &timeRange,
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "logAction",
@@ -290,17 +290,17 @@ func TestQuery_StartQuery(t *testing.T) {
},
}
timeRange := &tsdb.TimeRange{
timeRange := plugins.DataTimeRange{
From: "1584700643000",
To: "1584873443000",
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
TimeRange: timeRange,
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
TimeRange: &timeRange,
Queries: []plugins.DataSubQuery{
{
RefId: refID,
RefID: refID,
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "logAction",
"subtype": "StartQuery",
@@ -324,11 +324,11 @@ func TestQuery_StartQuery(t *testing.T) {
},
PreferredVisualization: "logs",
}
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
refID: {
Dataframes: tsdb.NewDecodedDataFrames(data.Frames{expFrame}),
RefId: refID,
Dataframes: plugins.NewDecodedDataFrames(data.Frames{expFrame}),
RefID: refID,
},
},
}, resp)
@@ -366,15 +366,15 @@ func TestQuery_StopQuery(t *testing.T) {
},
}
timeRange := &tsdb.TimeRange{
timeRange := plugins.DataTimeRange{
From: "1584873443000",
To: "1584700643000",
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
TimeRange: timeRange,
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
TimeRange: &timeRange,
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "logAction",
@@ -395,10 +395,10 @@ func TestQuery_StopQuery(t *testing.T) {
PreferredVisualization: "logs",
},
}
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Dataframes: tsdb.NewDecodedDataFrames(data.Frames{expFrame}),
Dataframes: plugins.NewDecodedDataFrames(data.Frames{expFrame}),
},
},
}, resp)
@@ -459,10 +459,10 @@ func TestQuery_GetQueryResults(t *testing.T) {
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
RefId: refID,
RefID: refID,
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "logAction",
"subtype": "GetQueryResults",
@@ -507,11 +507,11 @@ func TestQuery_GetQueryResults(t *testing.T) {
PreferredVisualization: "logs",
}
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
refID: {
RefId: refID,
Dataframes: tsdb.NewDecodedDataFrames(data.Frames{expFrame}),
RefID: refID,
Dataframes: plugins.NewDecodedDataFrames(data.Frames{expFrame}),
},
},
}, resp)
+5 -5
View File
@@ -4,8 +4,8 @@ import (
"fmt"
"sync"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/tsdb"
)
func init() {
@@ -15,19 +15,19 @@ func init() {
// LogsService provides methods for querying CloudWatch Logs.
type LogsService struct {
channelMu sync.Mutex
responseChannels map[string]chan *tsdb.Response
responseChannels map[string]chan plugins.DataResponse
queues map[string](chan bool)
queueLock sync.Mutex
}
// Init is called by the DI framework to initialize the instance.
func (s *LogsService) Init() error {
s.responseChannels = make(map[string]chan *tsdb.Response)
s.responseChannels = make(map[string]chan plugins.DataResponse)
s.queues = make(map[string](chan bool))
return nil
}
func (s *LogsService) AddResponseChannel(name string, channel chan *tsdb.Response) error {
func (s *LogsService) AddResponseChannel(name string, channel chan plugins.DataResponse) error {
s.channelMu.Lock()
defer s.channelMu.Unlock()
@@ -39,7 +39,7 @@ func (s *LogsService) AddResponseChannel(name string, channel chan *tsdb.Respons
return nil
}
func (s *LogsService) GetResponseChannel(name string) (chan *tsdb.Response, error) {
func (s *LogsService) GetResponseChannel(name string) (chan plugins.DataResponse, error) {
s.channelMu.Lock()
defer s.channelMu.Unlock()
+21 -20
View File
@@ -17,7 +17,7 @@ import (
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/util/errutil"
)
@@ -241,7 +241,8 @@ var dimensionsMap = map[string][]string{
var regionCache sync.Map
func (e *cloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
func (e *cloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queryContext plugins.DataQuery) (
plugins.DataResponse, error) {
firstQuery := queryContext.Queries[0]
parameters := firstQuery.Model
@@ -267,22 +268,22 @@ func (e *cloudWatchExecutor) executeMetricFindQuery(ctx context.Context, queryCo
data, err = e.handleGetResourceArns(ctx, parameters, queryContext)
}
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
queryResult := &tsdb.QueryResult{Meta: simplejson.New(), RefId: firstQuery.RefId}
transformToTable(data, queryResult)
result := &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
firstQuery.RefId: queryResult,
queryResult := plugins.DataQueryResult{Meta: simplejson.New(), RefID: firstQuery.RefID}
transformToTable(data, &queryResult)
result := plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
firstQuery.RefID: queryResult,
},
}
return result, nil
}
func transformToTable(data []suggestData, result *tsdb.QueryResult) {
table := &tsdb.Table{
Columns: []tsdb.TableColumn{
func transformToTable(data []suggestData, result *plugins.DataQueryResult) {
table := plugins.DataTable{
Columns: []plugins.DataTableColumn{
{
Text: "text",
},
@@ -290,7 +291,7 @@ func transformToTable(data []suggestData, result *tsdb.QueryResult) {
Text: "value",
},
},
Rows: make([]tsdb.RowValues, 0),
Rows: make([]plugins.DataRowValues, 0),
}
for _, r := range data {
@@ -321,7 +322,7 @@ func parseMultiSelectValue(input string) []string {
// Whenever this list is updated, the frontend list should also be updated.
// Please update the region list in public/app/plugins/datasource/cloudwatch/partials/config.html
func (e *cloudWatchExecutor) handleGetRegions(ctx context.Context, parameters *simplejson.Json,
queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
queryContext plugins.DataQuery) ([]suggestData, error) {
dsInfo := e.getDSInfo(defaultRegion)
profile := dsInfo.Profile
if cache, ok := regionCache.Load(profile); ok {
@@ -366,7 +367,7 @@ func (e *cloudWatchExecutor) handleGetRegions(ctx context.Context, parameters *s
return result, nil
}
func (e *cloudWatchExecutor) handleGetNamespaces(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
func (e *cloudWatchExecutor) handleGetNamespaces(ctx context.Context, parameters *simplejson.Json, queryContext plugins.DataQuery) ([]suggestData, error) {
keys := []string{}
for key := range metricsMap {
keys = append(keys, key)
@@ -385,7 +386,7 @@ func (e *cloudWatchExecutor) handleGetNamespaces(ctx context.Context, parameters
return result, nil
}
func (e *cloudWatchExecutor) handleGetMetrics(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
func (e *cloudWatchExecutor) handleGetMetrics(ctx context.Context, parameters *simplejson.Json, queryContext plugins.DataQuery) ([]suggestData, error) {
region := parameters.Get("region").MustString()
namespace := parameters.Get("namespace").MustString()
@@ -411,7 +412,7 @@ func (e *cloudWatchExecutor) handleGetMetrics(ctx context.Context, parameters *s
return result, nil
}
func (e *cloudWatchExecutor) handleGetDimensions(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
func (e *cloudWatchExecutor) handleGetDimensions(ctx context.Context, parameters *simplejson.Json, queryContext plugins.DataQuery) ([]suggestData, error) {
region := parameters.Get("region").MustString()
namespace := parameters.Get("namespace").MustString()
@@ -437,7 +438,7 @@ func (e *cloudWatchExecutor) handleGetDimensions(ctx context.Context, parameters
return result, nil
}
func (e *cloudWatchExecutor) handleGetDimensionValues(ctx context.Context, parameters *simplejson.Json, queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
func (e *cloudWatchExecutor) handleGetDimensionValues(ctx context.Context, parameters *simplejson.Json, queryContext plugins.DataQuery) ([]suggestData, error) {
region := parameters.Get("region").MustString()
namespace := parameters.Get("namespace").MustString()
metricName := parameters.Get("metricName").MustString()
@@ -489,7 +490,7 @@ func (e *cloudWatchExecutor) handleGetDimensionValues(ctx context.Context, param
}
func (e *cloudWatchExecutor) handleGetEbsVolumeIds(ctx context.Context, parameters *simplejson.Json,
queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
queryContext plugins.DataQuery) ([]suggestData, error) {
region := parameters.Get("region").MustString()
instanceId := parameters.Get("instanceId").MustString()
@@ -512,7 +513,7 @@ func (e *cloudWatchExecutor) handleGetEbsVolumeIds(ctx context.Context, paramete
}
func (e *cloudWatchExecutor) handleGetEc2InstanceAttribute(ctx context.Context, parameters *simplejson.Json,
queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
queryContext plugins.DataQuery) ([]suggestData, error) {
region := parameters.Get("region").MustString()
attributeName := parameters.Get("attributeName").MustString()
filterJson := parameters.Get("filters").MustMap()
@@ -592,7 +593,7 @@ func (e *cloudWatchExecutor) handleGetEc2InstanceAttribute(ctx context.Context,
}
func (e *cloudWatchExecutor) handleGetResourceArns(ctx context.Context, parameters *simplejson.Json,
queryContext *tsdb.TsdbQuery) ([]suggestData, error) {
queryContext plugins.DataQuery) ([]suggestData, error) {
region := parameters.Get("region").MustString()
resourceType := parameters.Get("resourceType").MustString()
filterJson := parameters.Get("tags").MustMap()
+43 -43
View File
@@ -14,7 +14,7 @@ import (
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi"
"github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi/resourcegroupstaggingapiiface"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -45,8 +45,8 @@ func TestQuery_Metrics(t *testing.T) {
},
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "metricFindQuery",
@@ -59,15 +59,15 @@ func TestQuery_Metrics(t *testing.T) {
})
require.NoError(t, err)
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Meta: simplejson.NewFromAny(map[string]interface{}{
"rowCount": 1,
}),
Tables: []*tsdb.Table{
Tables: []plugins.DataTable{
{
Columns: []tsdb.TableColumn{
Columns: []plugins.DataTableColumn{
{
Text: "text",
},
@@ -75,7 +75,7 @@ func TestQuery_Metrics(t *testing.T) {
Text: "value",
},
},
Rows: []tsdb.RowValues{
Rows: []plugins.DataRowValues{
{
"Test_MetricName",
"Test_MetricName",
@@ -102,8 +102,8 @@ func TestQuery_Metrics(t *testing.T) {
},
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "metricFindQuery",
@@ -116,15 +116,15 @@ func TestQuery_Metrics(t *testing.T) {
})
require.NoError(t, err)
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Meta: simplejson.NewFromAny(map[string]interface{}{
"rowCount": 1,
}),
Tables: []*tsdb.Table{
Tables: []plugins.DataTable{
{
Columns: []tsdb.TableColumn{
Columns: []plugins.DataTableColumn{
{
Text: "text",
},
@@ -132,7 +132,7 @@ func TestQuery_Metrics(t *testing.T) {
Text: "value",
},
},
Rows: []tsdb.RowValues{
Rows: []plugins.DataRowValues{
{
"Test_DimensionName",
"Test_DimensionName",
@@ -164,8 +164,8 @@ func TestQuery_Regions(t *testing.T) {
regions: []string{regionName},
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "metricFindQuery",
@@ -178,7 +178,7 @@ func TestQuery_Regions(t *testing.T) {
})
require.NoError(t, err)
rows := []tsdb.RowValues{}
rows := []plugins.DataRowValues{}
for _, region := range knownRegions {
rows = append(rows, []interface{}{
region,
@@ -189,15 +189,15 @@ func TestQuery_Regions(t *testing.T) {
regionName,
regionName,
})
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Meta: simplejson.NewFromAny(map[string]interface{}{
"rowCount": len(knownRegions) + 1,
}),
Tables: []*tsdb.Table{
Tables: []plugins.DataTable{
{
Columns: []tsdb.TableColumn{
Columns: []plugins.DataTableColumn{
{
Text: "text",
},
@@ -246,8 +246,8 @@ func TestQuery_InstanceAttributes(t *testing.T) {
},
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "metricFindQuery",
@@ -263,15 +263,15 @@ func TestQuery_InstanceAttributes(t *testing.T) {
})
require.NoError(t, err)
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Meta: simplejson.NewFromAny(map[string]interface{}{
"rowCount": 1,
}),
Tables: []*tsdb.Table{
Tables: []plugins.DataTable{
{
Columns: []tsdb.TableColumn{
Columns: []plugins.DataTableColumn{
{
Text: "text",
},
@@ -279,7 +279,7 @@ func TestQuery_InstanceAttributes(t *testing.T) {
Text: "value",
},
},
Rows: []tsdb.RowValues{
Rows: []plugins.DataRowValues{
{
instanceID,
instanceID,
@@ -349,8 +349,8 @@ func TestQuery_EBSVolumeIDs(t *testing.T) {
},
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "metricFindQuery",
@@ -363,15 +363,15 @@ func TestQuery_EBSVolumeIDs(t *testing.T) {
})
require.NoError(t, err)
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Meta: simplejson.NewFromAny(map[string]interface{}{
"rowCount": 6,
}),
Tables: []*tsdb.Table{
Tables: []plugins.DataTable{
{
Columns: []tsdb.TableColumn{
Columns: []plugins.DataTableColumn{
{
Text: "text",
},
@@ -379,7 +379,7 @@ func TestQuery_EBSVolumeIDs(t *testing.T) {
Text: "value",
},
},
Rows: []tsdb.RowValues{
Rows: []plugins.DataRowValues{
{
"vol-1-1",
"vol-1-1",
@@ -449,8 +449,8 @@ func TestQuery_ResourceARNs(t *testing.T) {
},
}
executor := newExecutor(nil)
resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
Queries: []*tsdb.Query{
resp, err := executor.DataQuery(context.Background(), fakeDataSource(), plugins.DataQuery{
Queries: []plugins.DataSubQuery{
{
Model: simplejson.NewFromAny(map[string]interface{}{
"type": "metricFindQuery",
@@ -466,15 +466,15 @@ func TestQuery_ResourceARNs(t *testing.T) {
})
require.NoError(t, err)
assert.Equal(t, &tsdb.Response{
Results: map[string]*tsdb.QueryResult{
assert.Equal(t, plugins.DataResponse{
Results: map[string]plugins.DataQueryResult{
"": {
Meta: simplejson.NewFromAny(map[string]interface{}{
"rowCount": 2,
}),
Tables: []*tsdb.Table{
Tables: []plugins.DataTable{
{
Columns: []tsdb.TableColumn{
Columns: []plugins.DataTableColumn{
{
Text: "text",
},
@@ -482,7 +482,7 @@ func TestQuery_ResourceARNs(t *testing.T) {
Text: "value",
},
},
Rows: []tsdb.RowValues{
Rows: []plugins.DataRowValues{
{
"arn:aws:ec2:us-east-1:123456789012:instance/i-12345678901234567",
"arn:aws:ec2:us-east-1:123456789012:instance/i-12345678901234567",
+13 -9
View File
@@ -9,7 +9,7 @@ import (
"time"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
)
// returns a map of queries with query id as key. In the case a q request query
@@ -55,7 +55,8 @@ func (e *cloudWatchExecutor) transformRequestQueriesToCloudWatchQueries(requestQ
return cloudwatchQueries, nil
}
func (e *cloudWatchExecutor) transformQueryResponsesToQueryResult(cloudwatchResponses []*cloudwatchResponse, requestQueries []*requestQuery, startTime time.Time, endTime time.Time) (map[string]*tsdb.QueryResult, error) {
func (e *cloudWatchExecutor) transformQueryResponsesToQueryResult(cloudwatchResponses []*cloudwatchResponse,
requestQueries []*requestQuery, startTime time.Time, endTime time.Time) (map[string]plugins.DataQueryResult, error) {
responsesByRefID := make(map[string][]*cloudwatchResponse)
refIDs := sort.StringSlice{}
for _, res := range cloudwatchResponses {
@@ -65,12 +66,13 @@ func (e *cloudWatchExecutor) transformQueryResponsesToQueryResult(cloudwatchResp
// Ensure stable results
refIDs.Sort()
results := make(map[string]*tsdb.QueryResult)
results := make(map[string]plugins.DataQueryResult)
for _, refID := range refIDs {
responses := responsesByRefID[refID]
queryResult := tsdb.NewQueryResult()
queryResult.RefId = refID
queryResult.Series = tsdb.TimeSeriesSlice{}
queryResult := plugins.DataQueryResult{
RefID: refID,
Series: plugins.DataTimeSeriesSlice{},
}
frames := make(data.Frames, 0, len(responses))
requestExceededMaxLimit := false
@@ -133,15 +135,17 @@ func (e *cloudWatchExecutor) transformQueryResponsesToQueryResult(cloudwatchResp
frame.Fields[1].Config.Links = createDataLinks(link)
}
queryResult.Dataframes = tsdb.NewDecodedDataFrames(frames)
queryResult.Dataframes = plugins.NewDecodedDataFrames(frames)
results[refID] = queryResult
}
return results, nil
}
// buildDeepLink generates a deep link from Grafana to the CloudWatch console. The link params are based on metric(s) for a given query row in the Query Editor.
func buildDeepLink(refID string, requestQueries []*requestQuery, executedQueries []executedQuery, startTime time.Time, endTime time.Time) (string, error) {
// buildDeepLink generates a deep link from Grafana to the CloudWatch console. The link params are based on
// metric(s) for a given query row in the Query Editor.
func buildDeepLink(refID string, requestQueries []*requestQuery, executedQueries []executedQuery, startTime time.Time,
endTime time.Time) (string, error) {
if isMathExpression(executedQueries) {
return "", nil
}
+4 -3
View File
@@ -11,11 +11,12 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
)
// Parses the json queries and returns a requestQuery. The requestQuery has a 1 to 1 mapping to a query editor row
func (e *cloudWatchExecutor) parseQueries(queryContext *tsdb.TsdbQuery, startTime time.Time, endTime time.Time) (map[string][]*requestQuery, error) {
func (e *cloudWatchExecutor) parseQueries(queryContext plugins.DataQuery, startTime time.Time,
endTime time.Time) (map[string][]*requestQuery, error) {
requestQueries := make(map[string][]*requestQuery)
for i, query := range queryContext.Queries {
queryType := query.Model.Get("type").MustString()
@@ -23,7 +24,7 @@ func (e *cloudWatchExecutor) parseQueries(queryContext *tsdb.TsdbQuery, startTim
continue
}
refID := query.RefId
refID := query.RefID
query, err := parseRequestQuery(queryContext.Queries[i].Model, refID, startTime, endTime)
if err != nil {
return nil, &queryError{err: err, RefID: refID}
+3 -3
View File
@@ -5,13 +5,13 @@ import (
"time"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRequestParser(t *testing.T) {
timeRange := tsdb.NewTimeRange("now-1h", "now-2h")
timeRange := plugins.NewDataTimeRange("now-1h", "now-2h")
from, err := timeRange.ParseFrom()
require.NoError(t, err)
to, err := timeRange.ParseTo()
@@ -102,7 +102,7 @@ func TestRequestParser(t *testing.T) {
"hide": false,
})
query.Set("period", "900")
timeRange := tsdb.NewTimeRange("now-1h", "now-2h")
timeRange := plugins.NewDataTimeRange("now-1h", "now-2h")
from, err := timeRange.ParseFrom()
require.NoError(t, err)
to, err := timeRange.ParseTo()
+23 -22
View File
@@ -5,37 +5,38 @@ import (
"fmt"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/util/errutil"
"golang.org/x/sync/errgroup"
)
func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryContext *tsdb.TsdbQuery) (*tsdb.Response, error) {
func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryContext plugins.DataQuery) (
plugins.DataResponse, error) {
plog.Debug("Executing time series query")
startTime, err := queryContext.TimeRange.ParseFrom()
if err != nil {
return nil, errutil.Wrap("failed to parse start time", err)
return plugins.DataResponse{}, errutil.Wrap("failed to parse start time", err)
}
endTime, err := queryContext.TimeRange.ParseTo()
if err != nil {
return nil, errutil.Wrap("failed to parse end time", err)
return plugins.DataResponse{}, errutil.Wrap("failed to parse end time", err)
}
if !startTime.Before(endTime) {
return nil, fmt.Errorf("invalid time range: start time must be before end time")
return plugins.DataResponse{}, fmt.Errorf("invalid time range: start time must be before end time")
}
requestQueriesByRegion, err := e.parseQueries(queryContext, startTime, endTime)
if err != nil {
return nil, err
return plugins.DataResponse{}, err
}
if len(requestQueriesByRegion) == 0 {
return &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult),
return plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
}, nil
}
resultChan := make(chan *tsdb.QueryResult, len(queryContext.Queries))
resultChan := make(chan plugins.DataQueryResult, len(queryContext.Queries))
eg, ectx := errgroup.WithContext(ctx)
for r, q := range requestQueriesByRegion {
requestQueries := q
@@ -45,7 +46,7 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
if err := recover(); err != nil {
plog.Error("Execute Get Metric Data Query Panic", "error", err, "stack", log.Stack(1))
if theErr, ok := err.(error); ok {
resultChan <- &tsdb.QueryResult{
resultChan <- plugins.DataQueryResult{
Error: theErr,
}
}
@@ -60,8 +61,8 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
queries, err := e.transformRequestQueriesToCloudWatchQueries(requestQueries)
if err != nil {
for _, query := range requestQueries {
resultChan <- &tsdb.QueryResult{
RefId: query.RefId,
resultChan <- plugins.DataQueryResult{
RefID: query.RefId,
Error: err,
}
}
@@ -77,8 +78,8 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
mdo, err := e.executeRequest(ectx, client, metricDataInput)
if err != nil {
for _, query := range requestQueries {
resultChan <- &tsdb.QueryResult{
RefId: query.RefId,
resultChan <- plugins.DataQueryResult{
RefID: query.RefId,
Error: err,
}
}
@@ -88,8 +89,8 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
responses, err := e.parseResponse(mdo, queries)
if err != nil {
for _, query := range requestQueries {
resultChan <- &tsdb.QueryResult{
RefId: query.RefId,
resultChan <- plugins.DataQueryResult{
RefID: query.RefId,
Error: err,
}
}
@@ -100,8 +101,8 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
res, err := e.transformQueryResponsesToQueryResult(cloudwatchResponses, requestQueries, startTime, endTime)
if err != nil {
for _, query := range requestQueries {
resultChan <- &tsdb.QueryResult{
RefId: query.RefId,
resultChan <- plugins.DataQueryResult{
RefID: query.RefId,
Error: err,
}
}
@@ -115,15 +116,15 @@ func (e *cloudWatchExecutor) executeTimeSeriesQuery(ctx context.Context, queryCo
})
}
if err := eg.Wait(); err != nil {
return nil, err
return plugins.DataResponse{}, err
}
close(resultChan)
results := &tsdb.Response{
Results: make(map[string]*tsdb.QueryResult),
results := plugins.DataResponse{
Results: make(map[string]plugins.DataQueryResult),
}
for result := range resultChan {
results.Results[result.RefId] = result
results.Results[result.RefID] = result
}
return results, nil
}
@@ -4,7 +4,7 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/tsdb"
"github.com/grafana/grafana/pkg/plugins"
"github.com/stretchr/testify/assert"
)
@@ -12,12 +12,16 @@ func TestTimeSeriesQuery(t *testing.T) {
executor := newExecutor(nil)
t.Run("End time before start time should result in error", func(t *testing.T) {
_, err := executor.executeTimeSeriesQuery(context.TODO(), &tsdb.TsdbQuery{TimeRange: tsdb.NewTimeRange("now-1h", "now-2h")})
timeRange := plugins.NewDataTimeRange("now-1h", "now-2h")
_, err := executor.executeTimeSeriesQuery(
context.TODO(), plugins.DataQuery{TimeRange: &timeRange})
assert.EqualError(t, err, "invalid time range: start time must be before end time")
})
t.Run("End time equals start time should result in error", func(t *testing.T) {
_, err := executor.executeTimeSeriesQuery(context.TODO(), &tsdb.TsdbQuery{TimeRange: tsdb.NewTimeRange("now-1h", "now-1h")})
timeRange := plugins.NewDataTimeRange("now-1h", "now-1h")
_, err := executor.executeTimeSeriesQuery(
context.TODO(), plugins.DataQuery{TimeRange: &timeRange})
assert.EqualError(t, err, "invalid time range: start time must be before end time")
})
}