Datasource: Shared HTTP client provider for core backend data sources and any data source using the data source proxy (#33439)
Uses new httpclient package from grafana-plugin-sdk-go introduced via grafana/grafana-plugin-sdk-go#328. Replaces the GetHTTPClient, GetTransport, GetTLSConfig methods defined on DataSource model. Longer-term the goal is to migrate core HTTP backend data sources to use the SDK contracts and using httpclient.Provider for creating HTTP clients and such. Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
co-authored by
Arve Knudsen
parent
7a83d1f9ff
commit
348e76fc8e
@@ -241,8 +241,6 @@ func (e *ApplicationInsightsDatasource) createRequest(ctx context.Context, dsInf
|
||||
return nil, errutil.Wrap("Failed to create request", err)
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion))
|
||||
|
||||
pluginproxy.ApplyRoute(ctx, req, proxyPass, appInsightsRoute, dsInfo, e.cfg)
|
||||
|
||||
return req, nil
|
||||
|
||||
@@ -221,7 +221,6 @@ func (e *AzureLogAnalyticsDatasource) createRequest(ctx context.Context, dsInfo
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion))
|
||||
|
||||
// find plugin
|
||||
plugin := e.pluginManager.GetDataSource(dsInfo.Type)
|
||||
|
||||
@@ -254,7 +254,6 @@ func (e *AzureMonitorDatasource) createRequest(ctx context.Context, dsInfo *mode
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion))
|
||||
|
||||
pluginproxy.ApplyRoute(ctx, req, proxyPass, azureMonitorRoute, dsInfo, e.cfg)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -29,8 +30,9 @@ func init() {
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
PluginManager plugins.Manager `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
PluginManager plugins.Manager `inject:""`
|
||||
HTTPClientProvider httpclient.Provider `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
}
|
||||
|
||||
func (s *Service) Init() error {
|
||||
@@ -48,7 +50,7 @@ type AzureMonitorExecutor struct {
|
||||
// NewAzureMonitorExecutor initializes a http client
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func (s *Service) NewExecutor(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
httpClient, err := dsInfo.GetHTTPClient(s.HTTPClientProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -215,8 +215,6 @@ func (e *InsightsAnalyticsDatasource) createRequest(ctx context.Context, dsInfo
|
||||
return nil, errutil.Wrap("Failed to create request", err)
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion))
|
||||
|
||||
pluginproxy.ApplyRoute(ctx, req, proxyPass, appInsightsRoute, dsInfo, e.cfg)
|
||||
|
||||
return req, nil
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/api/pluginproxy"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -75,8 +76,9 @@ func init() {
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
PluginManager plugins.Manager `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
PluginManager plugins.Manager `inject:""`
|
||||
HTTPClientProvider httpclient.Provider `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
}
|
||||
|
||||
func (s *Service) Init() error {
|
||||
@@ -94,7 +96,7 @@ type Executor struct {
|
||||
// NewExecutor returns an Executor.
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func (s *Service) NewExecutor(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
httpClient, err := dsInfo.GetHTTPClient(s.HTTPClientProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -540,7 +542,6 @@ func (e *Executor) createRequest(ctx context.Context, dsInfo *models.DataSource,
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion))
|
||||
|
||||
// find plugin
|
||||
plugin := e.pluginManager.GetDataSource(dsInfo.Type)
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/tsdb/interval"
|
||||
|
||||
@@ -29,8 +30,8 @@ var (
|
||||
clientLog = log.New(loggerName)
|
||||
)
|
||||
|
||||
var newDatasourceHttpClient = func(ds *models.DataSource) (*http.Client, error) {
|
||||
return ds.GetHttpClient()
|
||||
var newDatasourceHttpClient = func(httpClientProvider httpclient.Provider, ds *models.DataSource) (*http.Client, error) {
|
||||
return ds.GetHTTPClient(httpClientProvider)
|
||||
}
|
||||
|
||||
// Client represents a client which can interact with elasticsearch api
|
||||
@@ -72,7 +73,7 @@ func coerceVersion(v *simplejson.Json) (*semver.Version, error) {
|
||||
}
|
||||
|
||||
// NewClient creates a new elasticsearch client
|
||||
var NewClient = func(ctx context.Context, ds *models.DataSource, timeRange plugins.DataTimeRange) (Client, error) {
|
||||
var NewClient = func(ctx context.Context, httpClientProvider httpclient.Provider, ds *models.DataSource, timeRange plugins.DataTimeRange) (Client, error) {
|
||||
version, err := coerceVersion(ds.JsonData.Get("esVersion"))
|
||||
|
||||
if err != nil {
|
||||
@@ -108,13 +109,14 @@ var NewClient = func(ctx context.Context, ds *models.DataSource, timeRange plugi
|
||||
}
|
||||
|
||||
type baseClientImpl struct {
|
||||
ctx context.Context
|
||||
ds *models.DataSource
|
||||
version *semver.Version
|
||||
timeField string
|
||||
indices []string
|
||||
timeRange plugins.DataTimeRange
|
||||
debugEnabled bool
|
||||
ctx context.Context
|
||||
httpClientProvider httpclient.Provider
|
||||
ds *models.DataSource
|
||||
version *semver.Version
|
||||
timeField string
|
||||
indices []string
|
||||
timeRange plugins.DataTimeRange
|
||||
debugEnabled bool
|
||||
}
|
||||
|
||||
func (c *baseClientImpl) GetVersion() *semver.Version {
|
||||
@@ -208,20 +210,9 @@ func (c *baseClientImpl) executeRequest(method, uriPath, uriQuery string, body [
|
||||
}
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", "Grafana")
|
||||
req.Header.Set("Content-Type", "application/x-ndjson")
|
||||
|
||||
if c.ds.BasicAuth {
|
||||
clientLog.Debug("Request configured to use basic authentication")
|
||||
req.SetBasicAuth(c.ds.BasicAuthUser, c.ds.DecryptedBasicAuthPassword())
|
||||
}
|
||||
|
||||
if !c.ds.BasicAuth && c.ds.User != "" {
|
||||
clientLog.Debug("Request configured to use basic authentication")
|
||||
req.SetBasicAuth(c.ds.User, c.ds.DecryptedPassword())
|
||||
}
|
||||
|
||||
httpClient, err := newDatasourceHttpClient(c.ds)
|
||||
httpClient, err := newDatasourceHttpClient(c.httpClientProvider, c.ds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/tsdb/interval"
|
||||
@@ -24,7 +25,7 @@ func TestNewClient(t *testing.T) {
|
||||
JsonData: simplejson.NewFromAny(make(map[string]interface{})),
|
||||
}
|
||||
|
||||
_, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
_, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
@@ -35,7 +36,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
_, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
_, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
@@ -48,7 +49,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
_, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
_, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
@@ -60,7 +61,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
c, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
c, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "2.0.0", c.GetVersion().String())
|
||||
})
|
||||
@@ -73,7 +74,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
c, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
c, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "5.0.0", c.GetVersion().String())
|
||||
})
|
||||
@@ -86,7 +87,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
c, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
c, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "5.6.0", c.GetVersion().String())
|
||||
})
|
||||
@@ -99,7 +100,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
c, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
c, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "6.0.0", c.GetVersion().String())
|
||||
})
|
||||
@@ -112,7 +113,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
c, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
c, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "7.0.0", c.GetVersion().String())
|
||||
})
|
||||
@@ -127,7 +128,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
c, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
c, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, version, c.GetVersion().String())
|
||||
})
|
||||
@@ -141,7 +142,7 @@ func TestNewClient(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
_, err := NewClient(context.Background(), ds, plugins.DataTimeRange{})
|
||||
_, err := NewClient(context.Background(), httpclient.NewProvider(), ds, plugins.DataTimeRange{})
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
@@ -408,14 +409,14 @@ func httpClientScenario(t *testing.T, desc string, ds *models.DataSource, fn sce
|
||||
toStr := fmt.Sprintf("%d", to.UnixNano()/int64(time.Millisecond))
|
||||
timeRange := plugins.NewDataTimeRange(fromStr, toStr)
|
||||
|
||||
c, err := NewClient(context.Background(), ds, timeRange)
|
||||
c, err := NewClient(context.Background(), httpclient.NewProvider(), ds, timeRange)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, c)
|
||||
sc.client = c
|
||||
|
||||
currentNewDatasourceHTTPClient := newDatasourceHttpClient
|
||||
|
||||
newDatasourceHttpClient = func(ds *models.DataSource) (*http.Client, error) {
|
||||
newDatasourceHttpClient = func(httpClientProvider httpclient.Provider, ds *models.DataSource) (*http.Client, error) {
|
||||
return ts.Client(), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
es "github.com/grafana/grafana/pkg/tsdb/elasticsearch/client"
|
||||
@@ -12,15 +13,20 @@ import (
|
||||
|
||||
// ElasticsearchExecutor represents a handler for handling elasticsearch datasource request
|
||||
type Executor struct {
|
||||
httpClientProvider httpclient.Provider
|
||||
intervalCalculator interval.Calculator
|
||||
}
|
||||
|
||||
// NewExecutor creates a new Executor.
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func NewExecutor(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &Executor{
|
||||
intervalCalculator: interval.NewCalculator(),
|
||||
}, nil
|
||||
// New creates a new Executor func.
|
||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
||||
func New(httpClientProvider httpclient.Provider) func(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
||||
return func(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &Executor{
|
||||
httpClientProvider: httpClientProvider,
|
||||
intervalCalculator: interval.NewCalculator(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Query handles an elasticsearch datasource request
|
||||
@@ -31,8 +37,7 @@ func (e *Executor) DataQuery(ctx context.Context, dsInfo *models.DataSource,
|
||||
return plugins.DataResponse{}, fmt.Errorf("query contains no queries")
|
||||
}
|
||||
|
||||
client, err := es.NewClient(ctx, dsInfo, *tsdbQuery.TimeRange)
|
||||
|
||||
client, err := es.NewClient(ctx, e.httpClientProvider, dsInfo, *tsdbQuery.TimeRange)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -23,12 +24,17 @@ import (
|
||||
)
|
||||
|
||||
type GraphiteExecutor struct {
|
||||
HttpClient *http.Client
|
||||
httpClientProvider httpclient.Provider
|
||||
}
|
||||
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func NewExecutor(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &GraphiteExecutor{}, nil
|
||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
||||
func New(httpClientProvider httpclient.Provider) func(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
||||
return func(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &GraphiteExecutor{
|
||||
httpClientProvider: httpClientProvider,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
var glog = log.New("tsdb.graphite")
|
||||
@@ -91,7 +97,7 @@ func (e *GraphiteExecutor) DataQuery(ctx context.Context, dsInfo *models.DataSou
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
httpClient, err := dsInfo.GetHTTPClient(e.httpClientProvider)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/experimental"
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -226,7 +227,7 @@ func TestRealQuery(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
|
||||
runner, err := runnerFromDataSource(dsInfo)
|
||||
runner, err := runnerFromDataSource(httpclient.NewProvider(), dsInfo)
|
||||
require.NoError(t, err)
|
||||
|
||||
dr := executeQuery(context.Background(), queryModel{
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -22,13 +23,13 @@ func init() {
|
||||
|
||||
// Query builds flux queries, executes them, and returns the results.
|
||||
//nolint: staticcheck // plugins.DataQuery deprecated
|
||||
func Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery plugins.DataQuery) (
|
||||
func Query(ctx context.Context, httpClientProvider httpclient.Provider, dsInfo *models.DataSource, tsdbQuery plugins.DataQuery) (
|
||||
plugins.DataResponse, error) {
|
||||
glog.Debug("Received a query", "query", tsdbQuery)
|
||||
tRes := plugins.DataResponse{
|
||||
Results: make(map[string]plugins.DataQueryResult),
|
||||
}
|
||||
r, err := runnerFromDataSource(dsInfo)
|
||||
r, err := runnerFromDataSource(httpClientProvider, dsInfo)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
@@ -69,7 +70,7 @@ func (r *runner) runQuery(ctx context.Context, fluxQuery string) (*api.QueryTabl
|
||||
}
|
||||
|
||||
// runnerFromDataSource creates a runner from the datasource model (the datasource instance's configuration).
|
||||
func runnerFromDataSource(dsInfo *models.DataSource) (*runner, error) {
|
||||
func runnerFromDataSource(httpClientProvider httpclient.Provider, dsInfo *models.DataSource) (*runner, error) {
|
||||
org := dsInfo.JsonData.Get("organization").MustString("")
|
||||
if org == "" {
|
||||
return nil, fmt.Errorf("missing organization in datasource configuration")
|
||||
@@ -85,7 +86,7 @@ func runnerFromDataSource(dsInfo *models.DataSource) (*runner, error) {
|
||||
}
|
||||
|
||||
opts := influxdb2.DefaultOptions()
|
||||
hc, err := dsInfo.GetHttpClient()
|
||||
hc, err := dsInfo.GetHTTPClient(httpClientProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -17,17 +18,21 @@ import (
|
||||
)
|
||||
|
||||
type Executor struct {
|
||||
// *models.DataSource
|
||||
QueryParser *InfluxdbQueryParser
|
||||
ResponseParser *ResponseParser
|
||||
httpClientProvider httpclient.Provider
|
||||
QueryParser *InfluxdbQueryParser
|
||||
ResponseParser *ResponseParser
|
||||
}
|
||||
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func NewExecutor(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &Executor{
|
||||
QueryParser: &InfluxdbQueryParser{},
|
||||
ResponseParser: &ResponseParser{},
|
||||
}, nil
|
||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
||||
func New(httpClientProvider httpclient.Provider) func(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
||||
return func(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &Executor{
|
||||
httpClientProvider: httpClientProvider,
|
||||
QueryParser: &InfluxdbQueryParser{},
|
||||
ResponseParser: &ResponseParser{},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -47,7 +52,7 @@ func (e *Executor) DataQuery(ctx context.Context, dsInfo *models.DataSource, tsd
|
||||
|
||||
version := dsInfo.JsonData.Get("version").MustString("")
|
||||
if version == "Flux" {
|
||||
return flux.Query(ctx, dsInfo, tsdbQuery)
|
||||
return flux.Query(ctx, e.httpClientProvider, dsInfo, tsdbQuery)
|
||||
}
|
||||
|
||||
glog.Debug("Making a non-Flux type query")
|
||||
@@ -74,7 +79,7 @@ func (e *Executor) DataQuery(ctx context.Context, dsInfo *models.DataSource, tsd
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
httpClient, err := dsInfo.GetHTTPClient(e.httpClientProvider)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
+12
-10
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -23,16 +24,17 @@ import (
|
||||
|
||||
type LokiExecutor struct {
|
||||
intervalCalculator interval.Calculator
|
||||
httpClientProvider httpclient.Provider
|
||||
}
|
||||
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func NewExecutor(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
return newExecutor(), nil
|
||||
}
|
||||
|
||||
func newExecutor() *LokiExecutor {
|
||||
return &LokiExecutor{
|
||||
intervalCalculator: interval.NewCalculator(interval.CalculatorOptions{MinInterval: time.Second * 1}),
|
||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
||||
func New(httpClientProvider httpclient.Provider) func(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
// nolint:staticcheck // plugins.DataPlugin deprecated
|
||||
return func(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &LokiExecutor{
|
||||
intervalCalculator: interval.NewCalculator(interval.CalculatorOptions{MinInterval: time.Second * 1}),
|
||||
httpClientProvider: httpClientProvider,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,12 +51,12 @@ func (e *LokiExecutor) DataQuery(ctx context.Context, dsInfo *models.DataSource,
|
||||
Results: map[string]plugins.DataQueryResult{},
|
||||
}
|
||||
|
||||
tlsConfig, err := dsInfo.GetTLSConfig()
|
||||
tlsConfig, err := dsInfo.GetTLSConfig(e.httpClientProvider)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
transport, err := dsInfo.GetHttpTransport()
|
||||
transport, err := dsInfo.GetHTTPTransport(e.httpClientProvider)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/loki/pkg/loghttp"
|
||||
@@ -60,9 +61,10 @@ func TestLoki(t *testing.T) {
|
||||
TimeRange: &timeRange,
|
||||
}
|
||||
|
||||
exe := newExecutor()
|
||||
exe, err := New(httpclient.NewProvider())(dsInfo)
|
||||
require.NoError(t, err)
|
||||
models, err := exe.parseQuery(dsInfo, queryContext)
|
||||
lokiExecutor := exe.(*LokiExecutor)
|
||||
models, err := lokiExecutor.parseQuery(dsInfo, queryContext)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Second*30, models[0].Step)
|
||||
})
|
||||
@@ -82,15 +84,16 @@ func TestLoki(t *testing.T) {
|
||||
{Model: jsonModel},
|
||||
},
|
||||
}
|
||||
exe := newExecutor()
|
||||
exe, err := New(httpclient.NewProvider())(dsInfo)
|
||||
require.NoError(t, err)
|
||||
models, err := exe.parseQuery(dsInfo, queryContext)
|
||||
lokiExecutor := exe.(*LokiExecutor)
|
||||
models, err := lokiExecutor.parseQuery(dsInfo, queryContext)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Minute*2, models[0].Step)
|
||||
|
||||
timeRange = plugins.NewDataTimeRange("1h", "now")
|
||||
queryContext.TimeRange = &timeRange
|
||||
models, err = exe.parseQuery(dsInfo, queryContext)
|
||||
models, err = lokiExecutor.parseQuery(dsInfo, queryContext)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Second*2, models[0].Step)
|
||||
})
|
||||
|
||||
+41
-37
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/VividCortex/mysqlerr"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data/sqlutil"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
@@ -32,52 +33,55 @@ func characterEscape(s string, escapeChar string) string {
|
||||
}
|
||||
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func NewExecutor(datasource *models.DataSource) (plugins.DataPlugin, error) {
|
||||
logger := log.New("tsdb.mysql")
|
||||
func New(httpClientProvider httpclient.Provider) func(datasource *models.DataSource) (plugins.DataPlugin, error) {
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
return func(datasource *models.DataSource) (plugins.DataPlugin, error) {
|
||||
logger := log.New("tsdb.mysql")
|
||||
|
||||
protocol := "tcp"
|
||||
if strings.HasPrefix(datasource.Url, "/") {
|
||||
protocol = "unix"
|
||||
}
|
||||
protocol := "tcp"
|
||||
if strings.HasPrefix(datasource.Url, "/") {
|
||||
protocol = "unix"
|
||||
}
|
||||
|
||||
cnnstr := fmt.Sprintf("%s:%s@%s(%s)/%s?collation=utf8mb4_unicode_ci&parseTime=true&loc=UTC&allowNativePasswords=true",
|
||||
characterEscape(datasource.User, ":"),
|
||||
datasource.DecryptedPassword(),
|
||||
protocol,
|
||||
characterEscape(datasource.Url, ")"),
|
||||
characterEscape(datasource.Database, "?"),
|
||||
)
|
||||
cnnstr := fmt.Sprintf("%s:%s@%s(%s)/%s?collation=utf8mb4_unicode_ci&parseTime=true&loc=UTC&allowNativePasswords=true",
|
||||
characterEscape(datasource.User, ":"),
|
||||
datasource.DecryptedPassword(),
|
||||
protocol,
|
||||
characterEscape(datasource.Url, ")"),
|
||||
characterEscape(datasource.Database, "?"),
|
||||
)
|
||||
|
||||
tlsConfig, err := datasource.GetTLSConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tlsConfig.RootCAs != nil || len(tlsConfig.Certificates) > 0 {
|
||||
tlsConfigString := fmt.Sprintf("ds%d", datasource.Id)
|
||||
if err := mysql.RegisterTLSConfig(tlsConfigString, tlsConfig); err != nil {
|
||||
tlsConfig, err := datasource.GetTLSConfig(httpClientProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cnnstr += "&tls=" + tlsConfigString
|
||||
}
|
||||
|
||||
if setting.Env == setting.Dev {
|
||||
logger.Debug("getEngine", "connection", cnnstr)
|
||||
}
|
||||
if tlsConfig.RootCAs != nil || len(tlsConfig.Certificates) > 0 {
|
||||
tlsConfigString := fmt.Sprintf("ds%d", datasource.Id)
|
||||
if err := mysql.RegisterTLSConfig(tlsConfigString, tlsConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cnnstr += "&tls=" + tlsConfigString
|
||||
}
|
||||
|
||||
config := sqleng.DataPluginConfiguration{
|
||||
DriverName: "mysql",
|
||||
ConnectionString: cnnstr,
|
||||
Datasource: datasource,
|
||||
TimeColumnNames: []string{"time", "time_sec"},
|
||||
MetricColumnTypes: []string{"CHAR", "VARCHAR", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"},
|
||||
}
|
||||
if setting.Env == setting.Dev {
|
||||
logger.Debug("getEngine", "connection", cnnstr)
|
||||
}
|
||||
|
||||
rowTransformer := mysqlQueryResultTransformer{
|
||||
log: logger,
|
||||
}
|
||||
config := sqleng.DataPluginConfiguration{
|
||||
DriverName: "mysql",
|
||||
ConnectionString: cnnstr,
|
||||
Datasource: datasource,
|
||||
TimeColumnNames: []string{"time", "time_sec"},
|
||||
MetricColumnTypes: []string{"CHAR", "VARCHAR", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"},
|
||||
}
|
||||
|
||||
return sqleng.NewDataPlugin(config, &rowTransformer, newMysqlMacroEngine(logger), logger)
|
||||
rowTransformer := mysqlQueryResultTransformer{
|
||||
log: logger,
|
||||
}
|
||||
|
||||
return sqleng.NewDataPlugin(config, &rowTransformer, newMysqlMacroEngine(logger), logger)
|
||||
}
|
||||
}
|
||||
|
||||
type mysqlQueryResultTransformer struct {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
@@ -56,7 +57,7 @@ func TestMySQL(t *testing.T) {
|
||||
return sql, nil
|
||||
}
|
||||
|
||||
exe, err := NewExecutor(&models.DataSource{
|
||||
exe, err := New(httpclient.NewProvider())(&models.DataSource{
|
||||
JsonData: simplejson.New(),
|
||||
SecureJsonData: securejsondata.SecureJsonData{},
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"net/url"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -22,11 +23,17 @@ import (
|
||||
)
|
||||
|
||||
type OpenTsdbExecutor struct {
|
||||
httpClientProvider httpclient.Provider
|
||||
}
|
||||
|
||||
// nolint:staticcheck // plugins.DataQueryResult deprecated
|
||||
func NewExecutor(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &OpenTsdbExecutor{}, nil
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func New(httpClientProvider httpclient.Provider) func(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
return func(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &OpenTsdbExecutor{
|
||||
httpClientProvider: httpClientProvider,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -56,7 +63,7 @@ func (e *OpenTsdbExecutor) DataQuery(ctx context.Context, dsInfo *models.DataSou
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
httpClient, err := dsInfo.GetHTTPClient(e.httpClientProvider)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -65,13 +66,20 @@ func (transport *prometheusTransport) RoundTrip(req *http.Request) (*http.Respon
|
||||
}
|
||||
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func NewExecutor(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
return &PrometheusExecutor{
|
||||
intervalCalculator: interval.NewCalculator(interval.CalculatorOptions{MinInterval: time.Second * 1}),
|
||||
baseRoundTripperFactory: func(ds *models.DataSource) (http.RoundTripper, error) {
|
||||
return ds.GetHttpTransport()
|
||||
},
|
||||
}, nil
|
||||
func New(provider httpclient.Provider) func(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
return func(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
transport, err := dsInfo.GetHTTPTransport(provider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PrometheusExecutor{
|
||||
intervalCalculator: interval.NewCalculator(interval.CalculatorOptions{MinInterval: time.Second * 1}),
|
||||
baseRoundTripperFactory: func(ds *models.DataSource) (http.RoundTripper, error) {
|
||||
return transport, nil
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
p "github.com/prometheus/common/model"
|
||||
@@ -21,7 +22,7 @@ func TestPrometheus(t *testing.T) {
|
||||
dsInfo := &models.DataSource{
|
||||
JsonData: json,
|
||||
}
|
||||
plug, err := NewExecutor(dsInfo)
|
||||
plug, err := New(httpclient.NewProvider())(dsInfo)
|
||||
require.NoError(t, err)
|
||||
executor := plug.(*PrometheusExecutor)
|
||||
|
||||
|
||||
+10
-8
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
@@ -47,6 +48,7 @@ type Service struct {
|
||||
CloudMonitoringService *cloudmonitoring.Service `inject:""`
|
||||
AzureMonitorService *azuremonitor.Service `inject:""`
|
||||
PluginManager plugins.Manager `inject:""`
|
||||
HTTPClientProvider httpclient.Provider `inject:""`
|
||||
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
registry map[string]func(*models.DataSource) (plugins.DataPlugin, error)
|
||||
@@ -54,18 +56,18 @@ type Service struct {
|
||||
|
||||
// Init initialises the service.
|
||||
func (s *Service) Init() error {
|
||||
s.registry["graphite"] = graphite.NewExecutor
|
||||
s.registry["opentsdb"] = opentsdb.NewExecutor
|
||||
s.registry["prometheus"] = prometheus.NewExecutor
|
||||
s.registry["influxdb"] = influxdb.NewExecutor
|
||||
s.registry["graphite"] = graphite.New(s.HTTPClientProvider)
|
||||
s.registry["opentsdb"] = opentsdb.New(s.HTTPClientProvider)
|
||||
s.registry["prometheus"] = prometheus.New(s.HTTPClientProvider)
|
||||
s.registry["influxdb"] = influxdb.New(s.HTTPClientProvider)
|
||||
s.registry["mssql"] = mssql.NewExecutor
|
||||
s.registry["postgres"] = s.PostgresService.NewExecutor
|
||||
s.registry["mysql"] = mysql.NewExecutor
|
||||
s.registry["elasticsearch"] = elasticsearch.NewExecutor
|
||||
s.registry["mysql"] = mysql.New(s.HTTPClientProvider)
|
||||
s.registry["elasticsearch"] = elasticsearch.New(s.HTTPClientProvider)
|
||||
s.registry["stackdriver"] = s.CloudMonitoringService.NewExecutor
|
||||
s.registry["grafana-azure-monitor-datasource"] = s.AzureMonitorService.NewExecutor
|
||||
s.registry["loki"] = loki.NewExecutor
|
||||
s.registry["tempo"] = tempo.NewExecutor
|
||||
s.registry["loki"] = loki.New(s.HTTPClientProvider)
|
||||
s.registry["tempo"] = tempo.New(s.HTTPClientProvider)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+13
-9
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -18,17 +19,20 @@ type tempoExecutor struct {
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// NewExecutor returns a tempoExecutor.DataQueryResult
|
||||
// NewExecutor returns a tempoExecutor.
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func NewExecutor(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
httpClient, err := dsInfo.GetHttpClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func New(httpClientProvider httpclient.Provider) func(*models.DataSource) (plugins.DataPlugin, error) {
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
return func(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
httpClient, err := dsInfo.GetHTTPClient(httpClientProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tempoExecutor{
|
||||
httpClient: httpClient,
|
||||
}, nil
|
||||
return &tempoExecutor{
|
||||
httpClient: httpClient,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -4,13 +4,14 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTempo(t *testing.T) {
|
||||
plug, err := NewExecutor(&models.DataSource{})
|
||||
plug, err := New(httpclient.NewProvider())(&models.DataSource{})
|
||||
executor := plug.(*tempoExecutor)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user