From 2c7adccf12c8620d37dd4e9cef7d31b2d0de175d Mon Sep 17 00:00:00 2001 From: Carl Bergquist Date: Wed, 7 Dec 2016 11:10:42 +0100 Subject: [PATCH] Use cache for http.client in tsdb package. (#6833) * datasource: move caching closer to datasource struct * tsdb: use cached version of datasource http transport closes #6825 --- pkg/api/dataproxy.go | 75 +---------- pkg/api/dataproxy_test.go | 153 +-------------------- pkg/api/datasources.go | 3 +- pkg/api/metrics.go | 7 +- pkg/models/datasource_cache.go | 95 +++++++++++++ pkg/models/datasource_cache_test.go | 157 ++++++++++++++++++++++ pkg/services/alerting/conditions/query.go | 18 +-- pkg/tsdb/batch.go | 11 +- pkg/tsdb/executor.go | 22 ++- pkg/tsdb/fake_test.go | 10 +- pkg/tsdb/graphite/graphite.go | 24 ++-- pkg/tsdb/http.go | 29 ---- pkg/tsdb/influxdb/influxdb.go | 26 ++-- pkg/tsdb/influxdb/model_parser.go | 4 +- pkg/tsdb/influxdb/model_parser_test.go | 4 +- pkg/tsdb/models.go | 17 +-- pkg/tsdb/opentsdb/opentsdb.go | 24 ++-- pkg/tsdb/prometheus/prometheus.go | 21 ++- pkg/tsdb/testdata/testdata.go | 11 +- pkg/tsdb/tsdb_test.go | 37 ++--- 20 files changed, 385 insertions(+), 363 deletions(-) create mode 100644 pkg/models/datasource_cache.go create mode 100644 pkg/models/datasource_cache_test.go delete mode 100644 pkg/tsdb/http.go diff --git a/pkg/api/dataproxy.go b/pkg/api/dataproxy.go index 39de6911008..db4c5166feb 100644 --- a/pkg/api/dataproxy.go +++ b/pkg/api/dataproxy.go @@ -1,13 +1,9 @@ package api import ( - "crypto/tls" - "crypto/x509" - "net" "net/http" "net/http/httputil" "net/url" - "sync" "time" "github.com/grafana/grafana/pkg/api/cloudwatch" @@ -19,75 +15,6 @@ import ( "github.com/grafana/grafana/pkg/util" ) -type proxyTransportCache struct { - cache map[int64]cachedTransport - sync.Mutex -} - -type cachedTransport struct { - updated time.Time - - *http.Transport -} - -var ptc = proxyTransportCache{ - cache: make(map[int64]cachedTransport), -} - -func DataProxyTransport(ds *m.DataSource) (*http.Transport, error) { - ptc.Lock() - defer ptc.Unlock() - - if t, present := ptc.cache[ds.Id]; present && ds.Updated.Equal(t.updated) { - return t.Transport, nil - } - - transport := &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - Proxy: http.ProxyFromEnvironment, - Dial: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).Dial, - TLSHandshakeTimeout: 10 * time.Second, - } - - var tlsAuth, tlsAuthWithCACert bool - if ds.JsonData != nil { - tlsAuth = ds.JsonData.Get("tlsAuth").MustBool(false) - tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false) - } - - if tlsAuth { - transport.TLSClientConfig.InsecureSkipVerify = false - - decrypted := ds.SecureJsonData.Decrypt() - - if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 { - caPool := x509.NewCertPool() - ok := caPool.AppendCertsFromPEM([]byte(decrypted["tlsCACert"])) - if ok { - transport.TLSClientConfig.RootCAs = caPool - } - } - - cert, err := tls.X509KeyPair([]byte(decrypted["tlsClientCert"]), []byte(decrypted["tlsClientKey"])) - if err != nil { - return nil, err - } - transport.TLSClientConfig.Certificates = []tls.Certificate{cert} - } - - ptc.cache[ds.Id] = cachedTransport{ - Transport: transport, - updated: ds.Updated, - } - - return transport, nil -} - func NewReverseProxy(ds *m.DataSource, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy { director := func(req *http.Request) { req.URL.Scheme = targetUrl.Scheme @@ -189,7 +116,7 @@ func ProxyDataSourceRequest(c *middleware.Context) { } proxy := NewReverseProxy(ds, proxyPath, targetUrl) - proxy.Transport, err = DataProxyTransport(ds) + proxy.Transport, err = ds.GetHttpTransport() if err != nil { c.JsonApiErr(400, "Unable to load TLS certificate", err) return diff --git a/pkg/api/dataproxy_test.go b/pkg/api/dataproxy_test.go index 50abf317e8a..f3ed6994cff 100644 --- a/pkg/api/dataproxy_test.go +++ b/pkg/api/dataproxy_test.go @@ -4,24 +4,18 @@ import ( "net/http" "net/url" "testing" - "time" . "github.com/smartystreets/goconvey/convey" - "github.com/grafana/grafana/pkg/components/simplejson" m "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/util" ) func TestDataSourceProxy(t *testing.T) { - Convey("When getting graphite datasource proxy", t, func() { - clearCache() ds := m.DataSource{Url: "htttp://graphite:8080", Type: m.DS_GRAPHITE} targetUrl, err := url.Parse(ds.Url) proxy := NewReverseProxy(&ds, "/render", targetUrl) - proxy.Transport, err = DataProxyTransport(&ds) + proxy.Transport, err = ds.GetHttpTransport() So(err, ShouldBeNil) transport, ok := proxy.Transport.(*http.Transport) @@ -40,7 +34,6 @@ func TestDataSourceProxy(t *testing.T) { }) Convey("When getting influxdb datasource proxy", t, func() { - clearCache() ds := m.DataSource{ Type: m.DS_INFLUXDB_08, Url: "http://influxdb:8083", @@ -67,148 +60,4 @@ func TestDataSourceProxy(t *testing.T) { So(queryVals["p"][0], ShouldEqual, "password") }) }) - - Convey("When caching a datasource proxy", t, func() { - clearCache() - ds := m.DataSource{ - Id: 1, - Url: "http://k8s:8001", - Type: "Kubernetes", - } - - t1, err := DataProxyTransport(&ds) - So(err, ShouldBeNil) - - t2, err := DataProxyTransport(&ds) - So(err, ShouldBeNil) - - Convey("Should be using the cached proxy", func() { - So(t2, ShouldEqual, t1) - }) - }) - - Convey("When getting kubernetes datasource proxy", t, func() { - clearCache() - setting.SecretKey = "password" - - json := simplejson.New() - json.Set("tlsAuth", true) - json.Set("tlsAuthWithCACert", true) - - t := time.Now() - ds := m.DataSource{ - Url: "http://k8s:8001", - Type: "Kubernetes", - Updated: t.Add(-2 * time.Minute), - } - - transport, err := DataProxyTransport(&ds) - So(err, ShouldBeNil) - - Convey("Should have no cert", func() { - So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) - }) - - ds.JsonData = json - ds.SecureJsonData = map[string][]byte{ - "tlsCACert": util.Encrypt([]byte(caCert), "password"), - "tlsClientCert": util.Encrypt([]byte(clientCert), "password"), - "tlsClientKey": util.Encrypt([]byte(clientKey), "password"), - } - ds.Updated = t.Add(-1 * time.Minute) - - transport, err = DataProxyTransport(&ds) - So(err, ShouldBeNil) - - Convey("Should add cert", func() { - So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) - So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1) - }) - - ds.JsonData = nil - ds.SecureJsonData = map[string][]byte{} - ds.Updated = t - - transport, err = DataProxyTransport(&ds) - So(err, ShouldBeNil) - - Convey("Should remove cert", func() { - So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) - So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0) - }) - }) - } - -func clearCache() { - ptc.Lock() - defer ptc.Unlock() - - ptc.cache = make(map[int64]cachedTransport) -} - -const caCert string = `-----BEGIN CERTIFICATE----- -MIIDATCCAemgAwIBAgIJAMQ5hC3CPDTeMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV -BAMMDGNhLWs4cy1zdGhsbTAeFw0xNjEwMjcwODQyMjdaFw00NDAzMTQwODQyMjda -MBcxFTATBgNVBAMMDGNhLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAMLe2AmJ6IleeUt69vgNchOjjmxIIxz5sp1vFu94m1vUip7CqnOg -QkpUsHeBPrGYv8UGloARCL1xEWS+9FVZeXWQoDmbC0SxXhFwRIESNCET7Q8KMi/4 -4YPvnMLGZi3Fjwxa8BdUBCN1cx4WEooMVTWXm7RFMtZgDfuOAn3TNXla732sfT/d -1HNFrh48b0wA+HhmA3nXoBnBEblA665hCeo7lIAdRr0zJxJpnFnWXkyTClsAUTMN -iL905LdBiiIRenojipfKXvMz88XSaWTI7JjZYU3BvhyXndkT6f12cef3I96NY3WJ -0uIK4k04WrbzdYXMU3rN6NqlvbHqnI+E7aMCAwEAAaNQME4wHQYDVR0OBBYEFHHx -2+vSPw9bECHj3O51KNo5VdWOMB8GA1UdIwQYMBaAFHHx2+vSPw9bECHj3O51KNo5 -VdWOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH2eV5NcV3LBJHs9 -I+adbiTPg2vyumrGWwy73T0X8Dtchgt8wU7Q9b9Ucg2fOTmSSyS0iMqEu1Yb2ORB -CknM9mixHC9PwEBbkGCom3VVkqdLwSP6gdILZgyLoH4i8sTUz+S1yGPepi+Vzhs7 -adOXtryjcGnwft6HdfKPNklMOHFnjw6uqpho54oj/z55jUpicY/8glDHdrr1bh3k -MHuiWLGewHXPvxfG6UoUx1te65IhifVcJGFZDQwfEmhBflfCmtAJlZEsgTLlBBCh -FHoXIyGOdq1chmRVocdGBCF8fUoGIbuF14r53rpvcbEKtKnnP8+96luKAZLq0a4n -3lb92xM= ------END CERTIFICATE-----` - -const clientCert string = `-----BEGIN CERTIFICATE----- -MIICsjCCAZoCCQCcd8sOfstQLzANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxj -YS1rOHMtc3RobG0wHhcNMTYxMTAyMDkyNTE1WhcNMTcxMTAyMDkyNTE1WjAfMR0w -GwYDVQQDDBRhZG0tZGFuaWVsLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAOMliaWyNEUJKM37vWCl5bGub3lMicyRAqGQyY/qxD9yKKM2 -FbucVcmWmg5vvTqQVl5rlQ+c7GI8OD6ptmFl8a26coEki7bFr8bkpSyBSEc5p27b -Z0ORFSqBHWHQbr9PkxPLYW6T3gZYUtRYv3OQgGxLXlvUh85n/mQfuR3N1FgmShHo -GtAFi/ht6leXa0Ms+jNSDLCmXpJm1GIEqgyKX7K3+g3vzo9coYqXq4XTa8Efs2v8 -SCwqWfBC3rHfgs/5DLB8WT4Kul8QzxkytzcaBQfRfzhSV6bkgm7oTzt2/1eRRsf4 -YnXzLE9YkCC9sAn+Owzqf+TYC1KRluWDfqqBTJUCAwEAATANBgkqhkiG9w0BAQsF -AAOCAQEAdMsZg6edWGC+xngizn0uamrUg1ViaDqUsz0vpzY5NWLA4MsBc4EtxWRP -ueQvjUimZ3U3+AX0YWNLIrH1FCVos2jdij/xkTUmHcwzr8rQy+B17cFi+a8jtpgw -AU6WWoaAIEhhbWQfth/Diz3mivl1ARB+YqiWca2mjRPLTPcKJEURDVddQ423el0Q -4JNxS5icu7T2zYTYHAo/cT9zVdLZl0xuLxYm3asK1IONJ/evxyVZima3il6MPvhe -58Hwz+m+HdqHxi24b/1J/VKYbISG4huOQCdLzeNXgvwFlGPUmHSnnKo1/KbQDAR5 -llG/Sw5+FquFuChaA6l5KWy7F3bQyA== ------END CERTIFICATE-----` - -const clientKey string = `-----BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEA4yWJpbI0RQkozfu9YKXlsa5veUyJzJECoZDJj+rEP3IoozYV -u5xVyZaaDm+9OpBWXmuVD5zsYjw4Pqm2YWXxrbpygSSLtsWvxuSlLIFIRzmnbttn -Q5EVKoEdYdBuv0+TE8thbpPeBlhS1Fi/c5CAbEteW9SHzmf+ZB+5Hc3UWCZKEega -0AWL+G3qV5drQyz6M1IMsKZekmbUYgSqDIpfsrf6De/Oj1yhiperhdNrwR+za/xI -LCpZ8ELesd+Cz/kMsHxZPgq6XxDPGTK3NxoFB9F/OFJXpuSCbuhPO3b/V5FGx/hi -dfMsT1iQIL2wCf47DOp/5NgLUpGW5YN+qoFMlQIDAQABAoIBAQCzy4u312XeW1Cs -Mx6EuOwmh59/ESFmBkZh4rxZKYgrfE5EWlQ7i5SwG4BX+wR6rbNfy6JSmHDXlTkk -CKvvToVNcW6fYHEivDnVojhIERFIJ4+rhQmpBtcNLOQ3/4cZ8X/GxE6b+3lb5l+x -64mnjPLKRaIr5/+TVuebEy0xNTJmjnJ7yiB2HRz7uXEQaVSk/P7KAkkyl/9J3/LM -8N9AX1w6qDaNQZ4/P0++1H4SQenosM/b/GqGTomarEk/GE0NcB9rzmR9VCXa7FRh -WV5jyt9vUrwIEiK/6nUnOkGO8Ei3kB7Y+e+2m6WdaNoU5RAfqXmXa0Q/a0lLRruf -vTMo2WrBAoGBAPRaK4cx76Q+3SJ/wfznaPsMM06OSR8A3ctKdV+ip/lyKtb1W8Pz -k8MYQDH7GwPtSu5QD8doL00pPjugZL/ba7X9nAsI+pinyEErfnB9y7ORNEjIYYzs -DiqDKup7ANgw1gZvznWvb9Ge0WUSXvWS0pFkgootQAf+RmnnbWGH6l6RAoGBAO35 -aGUrLro5u9RD24uSXNU3NmojINIQFK5dHAT3yl0BBYstL43AEsye9lX95uMPTvOQ -Cqcn42Hjp/bSe3n0ObyOZeXVrWcDFAfE0wwB1BkvL1lpgnFO9+VQORlH4w3Ppnpo -jcPkR2TFeDaAYtvckhxe/Bk3OnuFmnsQ3VzM75fFAoGBAI6PvS2XeNU+yA3EtA01 -hg5SQ+zlHswz2TMuMeSmJZJnhY78f5mHlwIQOAPxGQXlf/4iP9J7en1uPpzTK3S0 -M9duK4hUqMA/w5oiIhbHjf0qDnMYVbG+V1V+SZ+cPBXmCDihKreGr5qBKnHpkfV8 -v9WL6o1rcRw4wiQvnaV1gsvBAoGBALtzVTczr6gDKCAIn5wuWy+cQSGTsBunjRLX -xuVm5iEiV+KMYkPvAx/pKzMLP96lRVR3ptyKgAKwl7LFk3u50+zh4gQLr35QH2wL -Lw7rNc3srAhrItPsFzqrWX6/cGuFoKYVS239l/sZzRppQPXcpb7xVvTp2whHcir0 -Wtnpl+TdAoGAGqKqo2KU3JoY3IuTDUk1dsNAm8jd9EWDh+s1x4aG4N79mwcss5GD -FF8MbFPneK7xQd8L6HisKUDAUi2NOyynM81LAftPkvN6ZuUVeFDfCL4vCA0HUXLD -+VrOhtUZkNNJlLMiVRJuQKUOGlg8PpObqYbstQAf/0/yFJMRHG82Tcg= ------END RSA PRIVATE KEY-----` diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go index cc305221817..a7254eeec6c 100644 --- a/pkg/api/datasources.go +++ b/pkg/api/datasources.go @@ -5,10 +5,9 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/bus" - "github.com/grafana/grafana/pkg/plugins" - //"github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/middleware" m "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/util" ) diff --git a/pkg/api/metrics.go b/pkg/api/metrics.go index 5516bdd52a5..dad3b159ad6 100644 --- a/pkg/api/metrics.go +++ b/pkg/api/metrics.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/middleware" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/tsdb" "github.com/grafana/grafana/pkg/tsdb/testdata" "github.com/grafana/grafana/pkg/util" @@ -25,9 +26,9 @@ func QueryMetrics(c *middleware.Context, reqDto dtos.MetricRequest) Response { MaxDataPoints: query.Get("maxDataPoints").MustInt64(100), IntervalMs: query.Get("intervalMs").MustInt64(1000), Model: query, - DataSource: &tsdb.DataSourceInfo{ - Name: "Grafana TestDataDB", - PluginId: "grafana-testdata-datasource", + DataSource: &models.DataSource{ + Name: "Grafana TestDataDB", + Type: "grafana-testdata-datasource", }, }) } diff --git a/pkg/models/datasource_cache.go b/pkg/models/datasource_cache.go new file mode 100644 index 00000000000..e32c0ac9e7c --- /dev/null +++ b/pkg/models/datasource_cache.go @@ -0,0 +1,95 @@ +package models + +import ( + "crypto/tls" + "crypto/x509" + "net" + "net/http" + "sync" + "time" +) + +type proxyTransportCache struct { + cache map[int64]cachedTransport + sync.Mutex +} + +type cachedTransport struct { + updated time.Time + + *http.Transport +} + +var ptc = proxyTransportCache{ + cache: make(map[int64]cachedTransport), +} + +func (ds *DataSource) GetHttpClient() (*http.Client, error) { + transport, err := ds.GetHttpTransport() + + if err != nil { + return nil, err + } + + return &http.Client{ + Timeout: time.Duration(30 * time.Second), + Transport: transport, + }, nil +} + +func (ds *DataSource) GetHttpTransport() (*http.Transport, error) { + ptc.Lock() + defer ptc.Unlock() + + if t, present := ptc.cache[ds.Id]; present && ds.Updated.Equal(t.updated) { + return t.Transport, nil + } + + transport := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + } + + var tlsAuth, tlsAuthWithCACert bool + if ds.JsonData != nil { + tlsAuth = ds.JsonData.Get("tlsAuth").MustBool(false) + tlsAuthWithCACert = ds.JsonData.Get("tlsAuthWithCACert").MustBool(false) + } + + if tlsAuth { + transport.TLSClientConfig.InsecureSkipVerify = false + + decrypted := ds.SecureJsonData.Decrypt() + + if tlsAuthWithCACert && len(decrypted["tlsCACert"]) > 0 { + caPool := x509.NewCertPool() + ok := caPool.AppendCertsFromPEM([]byte(decrypted["tlsCACert"])) + if ok { + transport.TLSClientConfig.RootCAs = caPool + } + } + + cert, err := tls.X509KeyPair([]byte(decrypted["tlsClientCert"]), []byte(decrypted["tlsClientKey"])) + if err != nil { + return nil, err + } + transport.TLSClientConfig.Certificates = []tls.Certificate{cert} + } + + ptc.cache[ds.Id] = cachedTransport{ + Transport: transport, + updated: ds.Updated, + } + + return transport, nil +} diff --git a/pkg/models/datasource_cache_test.go b/pkg/models/datasource_cache_test.go new file mode 100644 index 00000000000..25fee55529d --- /dev/null +++ b/pkg/models/datasource_cache_test.go @@ -0,0 +1,157 @@ +package models + +import ( + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/util" +) + +func TestDataSourceCache(t *testing.T) { + Convey("When caching a datasource proxy", t, func() { + clearCache() + ds := DataSource{ + Id: 1, + Url: "http://k8s:8001", + Type: "Kubernetes", + } + + t1, err := ds.GetHttpTransport() + So(err, ShouldBeNil) + + t2, err := ds.GetHttpTransport() + So(err, ShouldBeNil) + + Convey("Should be using the cached proxy", func() { + So(t2, ShouldEqual, t1) + }) + }) + + Convey("When getting kubernetes datasource proxy", t, func() { + clearCache() + setting.SecretKey = "password" + + json := simplejson.New() + json.Set("tlsAuth", true) + json.Set("tlsAuthWithCACert", true) + + t := time.Now() + ds := DataSource{ + Url: "http://k8s:8001", + Type: "Kubernetes", + Updated: t.Add(-2 * time.Minute), + } + + transport, err := ds.GetHttpTransport() + So(err, ShouldBeNil) + + Convey("Should have no cert", func() { + So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) + }) + + ds.JsonData = json + ds.SecureJsonData = map[string][]byte{ + "tlsCACert": util.Encrypt([]byte(caCert), "password"), + "tlsClientCert": util.Encrypt([]byte(clientCert), "password"), + "tlsClientKey": util.Encrypt([]byte(clientKey), "password"), + } + ds.Updated = t.Add(-1 * time.Minute) + + transport, err = ds.GetHttpTransport() + So(err, ShouldBeNil) + + Convey("Should add cert", func() { + So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) + So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1) + }) + + ds.JsonData = nil + ds.SecureJsonData = map[string][]byte{} + ds.Updated = t + + transport, err = ds.GetHttpTransport() + So(err, ShouldBeNil) + + Convey("Should remove cert", func() { + So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, true) + So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 0) + }) + }) +} + +func clearCache() { + ptc.Lock() + defer ptc.Unlock() + + ptc.cache = make(map[int64]cachedTransport) +} + +const caCert string = `-----BEGIN CERTIFICATE----- +MIIDATCCAemgAwIBAgIJAMQ5hC3CPDTeMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV +BAMMDGNhLWs4cy1zdGhsbTAeFw0xNjEwMjcwODQyMjdaFw00NDAzMTQwODQyMjda +MBcxFTATBgNVBAMMDGNhLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMLe2AmJ6IleeUt69vgNchOjjmxIIxz5sp1vFu94m1vUip7CqnOg +QkpUsHeBPrGYv8UGloARCL1xEWS+9FVZeXWQoDmbC0SxXhFwRIESNCET7Q8KMi/4 +4YPvnMLGZi3Fjwxa8BdUBCN1cx4WEooMVTWXm7RFMtZgDfuOAn3TNXla732sfT/d +1HNFrh48b0wA+HhmA3nXoBnBEblA665hCeo7lIAdRr0zJxJpnFnWXkyTClsAUTMN +iL905LdBiiIRenojipfKXvMz88XSaWTI7JjZYU3BvhyXndkT6f12cef3I96NY3WJ +0uIK4k04WrbzdYXMU3rN6NqlvbHqnI+E7aMCAwEAAaNQME4wHQYDVR0OBBYEFHHx +2+vSPw9bECHj3O51KNo5VdWOMB8GA1UdIwQYMBaAFHHx2+vSPw9bECHj3O51KNo5 +VdWOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH2eV5NcV3LBJHs9 +I+adbiTPg2vyumrGWwy73T0X8Dtchgt8wU7Q9b9Ucg2fOTmSSyS0iMqEu1Yb2ORB +CknM9mixHC9PwEBbkGCom3VVkqdLwSP6gdILZgyLoH4i8sTUz+S1yGPepi+Vzhs7 +adOXtryjcGnwft6HdfKPNklMOHFnjw6uqpho54oj/z55jUpicY/8glDHdrr1bh3k +MHuiWLGewHXPvxfG6UoUx1te65IhifVcJGFZDQwfEmhBflfCmtAJlZEsgTLlBBCh +FHoXIyGOdq1chmRVocdGBCF8fUoGIbuF14r53rpvcbEKtKnnP8+96luKAZLq0a4n +3lb92xM= +-----END CERTIFICATE-----` + +const clientCert string = `-----BEGIN CERTIFICATE----- +MIICsjCCAZoCCQCcd8sOfstQLzANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxj +YS1rOHMtc3RobG0wHhcNMTYxMTAyMDkyNTE1WhcNMTcxMTAyMDkyNTE1WjAfMR0w +GwYDVQQDDBRhZG0tZGFuaWVsLWs4cy1zdGhsbTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAOMliaWyNEUJKM37vWCl5bGub3lMicyRAqGQyY/qxD9yKKM2 +FbucVcmWmg5vvTqQVl5rlQ+c7GI8OD6ptmFl8a26coEki7bFr8bkpSyBSEc5p27b +Z0ORFSqBHWHQbr9PkxPLYW6T3gZYUtRYv3OQgGxLXlvUh85n/mQfuR3N1FgmShHo +GtAFi/ht6leXa0Ms+jNSDLCmXpJm1GIEqgyKX7K3+g3vzo9coYqXq4XTa8Efs2v8 +SCwqWfBC3rHfgs/5DLB8WT4Kul8QzxkytzcaBQfRfzhSV6bkgm7oTzt2/1eRRsf4 +YnXzLE9YkCC9sAn+Owzqf+TYC1KRluWDfqqBTJUCAwEAATANBgkqhkiG9w0BAQsF +AAOCAQEAdMsZg6edWGC+xngizn0uamrUg1ViaDqUsz0vpzY5NWLA4MsBc4EtxWRP +ueQvjUimZ3U3+AX0YWNLIrH1FCVos2jdij/xkTUmHcwzr8rQy+B17cFi+a8jtpgw +AU6WWoaAIEhhbWQfth/Diz3mivl1ARB+YqiWca2mjRPLTPcKJEURDVddQ423el0Q +4JNxS5icu7T2zYTYHAo/cT9zVdLZl0xuLxYm3asK1IONJ/evxyVZima3il6MPvhe +58Hwz+m+HdqHxi24b/1J/VKYbISG4huOQCdLzeNXgvwFlGPUmHSnnKo1/KbQDAR5 +llG/Sw5+FquFuChaA6l5KWy7F3bQyA== +-----END CERTIFICATE-----` + +const clientKey string = `-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA4yWJpbI0RQkozfu9YKXlsa5veUyJzJECoZDJj+rEP3IoozYV +u5xVyZaaDm+9OpBWXmuVD5zsYjw4Pqm2YWXxrbpygSSLtsWvxuSlLIFIRzmnbttn +Q5EVKoEdYdBuv0+TE8thbpPeBlhS1Fi/c5CAbEteW9SHzmf+ZB+5Hc3UWCZKEega +0AWL+G3qV5drQyz6M1IMsKZekmbUYgSqDIpfsrf6De/Oj1yhiperhdNrwR+za/xI +LCpZ8ELesd+Cz/kMsHxZPgq6XxDPGTK3NxoFB9F/OFJXpuSCbuhPO3b/V5FGx/hi +dfMsT1iQIL2wCf47DOp/5NgLUpGW5YN+qoFMlQIDAQABAoIBAQCzy4u312XeW1Cs +Mx6EuOwmh59/ESFmBkZh4rxZKYgrfE5EWlQ7i5SwG4BX+wR6rbNfy6JSmHDXlTkk +CKvvToVNcW6fYHEivDnVojhIERFIJ4+rhQmpBtcNLOQ3/4cZ8X/GxE6b+3lb5l+x +64mnjPLKRaIr5/+TVuebEy0xNTJmjnJ7yiB2HRz7uXEQaVSk/P7KAkkyl/9J3/LM +8N9AX1w6qDaNQZ4/P0++1H4SQenosM/b/GqGTomarEk/GE0NcB9rzmR9VCXa7FRh +WV5jyt9vUrwIEiK/6nUnOkGO8Ei3kB7Y+e+2m6WdaNoU5RAfqXmXa0Q/a0lLRruf +vTMo2WrBAoGBAPRaK4cx76Q+3SJ/wfznaPsMM06OSR8A3ctKdV+ip/lyKtb1W8Pz +k8MYQDH7GwPtSu5QD8doL00pPjugZL/ba7X9nAsI+pinyEErfnB9y7ORNEjIYYzs +DiqDKup7ANgw1gZvznWvb9Ge0WUSXvWS0pFkgootQAf+RmnnbWGH6l6RAoGBAO35 +aGUrLro5u9RD24uSXNU3NmojINIQFK5dHAT3yl0BBYstL43AEsye9lX95uMPTvOQ +Cqcn42Hjp/bSe3n0ObyOZeXVrWcDFAfE0wwB1BkvL1lpgnFO9+VQORlH4w3Ppnpo +jcPkR2TFeDaAYtvckhxe/Bk3OnuFmnsQ3VzM75fFAoGBAI6PvS2XeNU+yA3EtA01 +hg5SQ+zlHswz2TMuMeSmJZJnhY78f5mHlwIQOAPxGQXlf/4iP9J7en1uPpzTK3S0 +M9duK4hUqMA/w5oiIhbHjf0qDnMYVbG+V1V+SZ+cPBXmCDihKreGr5qBKnHpkfV8 +v9WL6o1rcRw4wiQvnaV1gsvBAoGBALtzVTczr6gDKCAIn5wuWy+cQSGTsBunjRLX +xuVm5iEiV+KMYkPvAx/pKzMLP96lRVR3ptyKgAKwl7LFk3u50+zh4gQLr35QH2wL +Lw7rNc3srAhrItPsFzqrWX6/cGuFoKYVS239l/sZzRppQPXcpb7xVvTp2whHcir0 +Wtnpl+TdAoGAGqKqo2KU3JoY3IuTDUk1dsNAm8jd9EWDh+s1x4aG4N79mwcss5GD +FF8MbFPneK7xQd8L6HisKUDAUi2NOyynM81LAftPkvN6ZuUVeFDfCL4vCA0HUXLD ++VrOhtUZkNNJlLMiVRJuQKUOGlg8PpObqYbstQAf/0/yFJMRHG82Tcg= +-----END RSA PRIVATE KEY-----` diff --git a/pkg/services/alerting/conditions/query.go b/pkg/services/alerting/conditions/query.go index e58dbf1d583..d7e0a0c29e3 100644 --- a/pkg/services/alerting/conditions/query.go +++ b/pkg/services/alerting/conditions/query.go @@ -119,21 +119,9 @@ func (c *QueryCondition) getRequestForAlertRule(datasource *m.DataSource, timeRa TimeRange: timeRange, Queries: []*tsdb.Query{ { - RefId: "A", - Model: c.Query.Model, - DataSource: &tsdb.DataSourceInfo{ - Id: datasource.Id, - Name: datasource.Name, - PluginId: datasource.Type, - Url: datasource.Url, - User: datasource.User, - Password: datasource.Password, - Database: datasource.Database, - BasicAuth: datasource.BasicAuth, - BasicAuthUser: datasource.BasicAuthUser, - BasicAuthPassword: datasource.BasicAuthPassword, - JsonData: datasource.JsonData, - }, + RefId: "A", + Model: c.Query.Model, + DataSource: datasource, }, }, } diff --git a/pkg/tsdb/batch.go b/pkg/tsdb/batch.go index 284a158bf5f..8130ac94b0d 100644 --- a/pkg/tsdb/batch.go +++ b/pkg/tsdb/batch.go @@ -1,9 +1,6 @@ package tsdb -import ( - "context" - "errors" -) +import "context" type Batch struct { DataSourceId int64 @@ -24,12 +21,12 @@ func newBatch(dsId int64, queries QuerySlice) *Batch { } func (bg *Batch) process(ctx context.Context, queryContext *QueryContext) { - executor := getExecutorFor(bg.Queries[0].DataSource) + executor, err := getExecutorFor(bg.Queries[0].DataSource) - if executor == nil { + if err != nil { bg.Done = true result := &BatchResult{ - Error: errors.New("Could not find executor for data source type: " + bg.Queries[0].DataSource.PluginId), + Error: err, QueryResults: make(map[string]*QueryResult), } for _, query := range bg.Queries { diff --git a/pkg/tsdb/executor.go b/pkg/tsdb/executor.go index cc1d592dcd5..251b3dc947a 100644 --- a/pkg/tsdb/executor.go +++ b/pkg/tsdb/executor.go @@ -1,6 +1,11 @@ package tsdb -import "context" +import ( + "context" + "fmt" + + "github.com/grafana/grafana/pkg/models" +) type Executor interface { Execute(ctx context.Context, queries QuerySlice, query *QueryContext) *BatchResult @@ -8,17 +13,22 @@ type Executor interface { var registry map[string]GetExecutorFn -type GetExecutorFn func(dsInfo *DataSourceInfo) Executor +type GetExecutorFn func(dsInfo *models.DataSource) (Executor, error) func init() { registry = make(map[string]GetExecutorFn) } -func getExecutorFor(dsInfo *DataSourceInfo) Executor { - if fn, exists := registry[dsInfo.PluginId]; exists { - return fn(dsInfo) +func getExecutorFor(dsInfo *models.DataSource) (Executor, error) { + if fn, exists := registry[dsInfo.Type]; exists { + executor, err := fn(dsInfo) + if err != nil { + return nil, err + } + + return executor, nil } - return nil + return nil, fmt.Errorf("Could not find executor for data source type: %s", dsInfo.Type) } func RegisterExecutor(pluginId string, fn GetExecutorFn) { diff --git a/pkg/tsdb/fake_test.go b/pkg/tsdb/fake_test.go index c403fdba4fb..3c773971240 100644 --- a/pkg/tsdb/fake_test.go +++ b/pkg/tsdb/fake_test.go @@ -1,6 +1,10 @@ package tsdb -import "context" +import ( + "context" + + "github.com/grafana/grafana/pkg/models" +) type FakeExecutor struct { results map[string]*QueryResult @@ -9,11 +13,11 @@ type FakeExecutor struct { type ResultsFn func(context *QueryContext) *QueryResult -func NewFakeExecutor(dsInfo *DataSourceInfo) *FakeExecutor { +func NewFakeExecutor(dsInfo *models.DataSource) (*FakeExecutor, error) { return &FakeExecutor{ results: make(map[string]*QueryResult), resultsFn: make(map[string]ResultsFn), - } + }, nil } func (e *FakeExecutor) Execute(ctx context.Context, queries QuerySlice, context *QueryContext) *BatchResult { diff --git a/pkg/tsdb/graphite/graphite.go b/pkg/tsdb/graphite/graphite.go index 3d6af5beb5b..a467e839b82 100644 --- a/pkg/tsdb/graphite/graphite.go +++ b/pkg/tsdb/graphite/graphite.go @@ -14,28 +14,36 @@ import ( "golang.org/x/net/context/ctxhttp" "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb" ) type GraphiteExecutor struct { - *tsdb.DataSourceInfo + *models.DataSource + HttpClient *http.Client } -func NewGraphiteExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { - return &GraphiteExecutor{dsInfo} +func NewGraphiteExecutor(datasource *models.DataSource) (tsdb.Executor, error) { + httpClient, err := datasource.GetHttpClient() + + if err != nil { + return nil, err + } + + return &GraphiteExecutor{ + DataSource: datasource, + HttpClient: httpClient, + }, nil } var ( - glog log.Logger - HttpClient *http.Client + glog log.Logger ) func init() { glog = log.New("tsdb.graphite") tsdb.RegisterExecutor("graphite", NewGraphiteExecutor) - - HttpClient = tsdb.GetDefaultClient() } func (e *GraphiteExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, context *tsdb.QueryContext) *tsdb.BatchResult { @@ -66,7 +74,7 @@ func (e *GraphiteExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, return result } - res, err := ctxhttp.Do(ctx, HttpClient, req) + res, err := ctxhttp.Do(ctx, e.HttpClient, req) if err != nil { result.Error = err return result diff --git a/pkg/tsdb/http.go b/pkg/tsdb/http.go deleted file mode 100644 index f5de146d470..00000000000 --- a/pkg/tsdb/http.go +++ /dev/null @@ -1,29 +0,0 @@ -package tsdb - -import ( - "crypto/tls" - "net" - "net/http" - "time" -) - -func GetDefaultClient() *http.Client { - tr := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).DialContext, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - - return &http.Client{ - Timeout: time.Duration(30 * time.Second), - Transport: tr, - } -} diff --git a/pkg/tsdb/influxdb/influxdb.go b/pkg/tsdb/influxdb/influxdb.go index 658fbcff023..21d359d24bf 100644 --- a/pkg/tsdb/influxdb/influxdb.go +++ b/pkg/tsdb/influxdb/influxdb.go @@ -11,34 +11,40 @@ import ( "golang.org/x/net/context/ctxhttp" "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb" ) type InfluxDBExecutor struct { - *tsdb.DataSourceInfo + *models.DataSource QueryParser *InfluxdbQueryParser ResponseParser *ResponseParser + HttpClient *http.Client } -func NewInfluxDBExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { +func NewInfluxDBExecutor(datasource *models.DataSource) (tsdb.Executor, error) { + httpClient, err := datasource.GetHttpClient() + + if err != nil { + return nil, err + } + return &InfluxDBExecutor{ - DataSourceInfo: dsInfo, + DataSource: datasource, QueryParser: &InfluxdbQueryParser{}, ResponseParser: &ResponseParser{}, - } + HttpClient: httpClient, + }, nil } var ( - glog log.Logger - HttpClient *http.Client + glog log.Logger ) func init() { glog = log.New("tsdb.influxdb") tsdb.RegisterExecutor("influxdb", NewInfluxDBExecutor) - - HttpClient = tsdb.GetDefaultClient() } func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, context *tsdb.QueryContext) *tsdb.BatchResult { @@ -63,7 +69,7 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, return result.WithError(err) } - resp, err := ctxhttp.Do(ctx, HttpClient, req) + resp, err := ctxhttp.Do(ctx, e.HttpClient, req) if err != nil { return result.WithError(err) } @@ -95,7 +101,7 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, func (e *InfluxDBExecutor) getQuery(queries tsdb.QuerySlice, context *tsdb.QueryContext) (*Query, error) { for _, v := range queries { - query, err := e.QueryParser.Parse(v.Model, e.DataSourceInfo) + query, err := e.QueryParser.Parse(v.Model, e.DataSource) if err != nil { return nil, err } diff --git a/pkg/tsdb/influxdb/model_parser.go b/pkg/tsdb/influxdb/model_parser.go index 410bf8f6e82..f3d87739e5b 100644 --- a/pkg/tsdb/influxdb/model_parser.go +++ b/pkg/tsdb/influxdb/model_parser.go @@ -4,12 +4,12 @@ import ( "strconv" "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/tsdb" + "github.com/grafana/grafana/pkg/models" ) type InfluxdbQueryParser struct{} -func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json, dsInfo *tsdb.DataSourceInfo) (*Query, error) { +func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json, dsInfo *models.DataSource) (*Query, error) { policy := model.Get("policy").MustString("default") rawQuery := model.Get("query").MustString("") useRawQuery := model.Get("rawQuery").MustBool(false) diff --git a/pkg/tsdb/influxdb/model_parser_test.go b/pkg/tsdb/influxdb/model_parser_test.go index eae6e163cc0..f7049efb9a7 100644 --- a/pkg/tsdb/influxdb/model_parser_test.go +++ b/pkg/tsdb/influxdb/model_parser_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/grafana/grafana/pkg/components/simplejson" - "github.com/grafana/grafana/pkg/tsdb" + "github.com/grafana/grafana/pkg/models" . "github.com/smartystreets/goconvey/convey" ) @@ -12,7 +12,7 @@ func TestInfluxdbQueryParser(t *testing.T) { Convey("Influxdb query parser", t, func() { parser := &InfluxdbQueryParser{} - dsInfo := &tsdb.DataSourceInfo{ + dsInfo := &models.DataSource{ JsonData: simplejson.New(), } diff --git a/pkg/tsdb/models.go b/pkg/tsdb/models.go index 366709cfba7..e95713e7077 100644 --- a/pkg/tsdb/models.go +++ b/pkg/tsdb/models.go @@ -2,6 +2,7 @@ package tsdb import ( "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" "gopkg.in/guregu/null.v3" ) @@ -9,7 +10,7 @@ type Query struct { RefId string Model *simplejson.Json Depends []string - DataSource *DataSourceInfo + DataSource *models.DataSource Results []*TimeSeries Exclude bool MaxDataPoints int64 @@ -28,20 +29,6 @@ type Response struct { Results map[string]*QueryResult `json:"results"` } -type DataSourceInfo struct { - Id int64 - Name string - PluginId string - Url string - Password string - User string - Database string - BasicAuth bool - BasicAuthUser string - BasicAuthPassword string - JsonData *simplejson.Json -} - type BatchTiming struct { TimeElapsed int64 } diff --git a/pkg/tsdb/opentsdb/opentsdb.go b/pkg/tsdb/opentsdb/opentsdb.go index c5e5b0020d1..f5b6ffda7d2 100644 --- a/pkg/tsdb/opentsdb/opentsdb.go +++ b/pkg/tsdb/opentsdb/opentsdb.go @@ -17,28 +17,36 @@ import ( "gopkg.in/guregu/null.v3" "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tsdb" ) type OpenTsdbExecutor struct { - *tsdb.DataSourceInfo + *models.DataSource + httpClient *http.Client } -func NewOpenTsdbExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { - return &OpenTsdbExecutor{dsInfo} +func NewOpenTsdbExecutor(datasource *models.DataSource) (tsdb.Executor, error) { + httpClient, err := datasource.GetHttpClient() + + if err != nil { + return nil, err + } + + return &OpenTsdbExecutor{ + DataSource: datasource, + httpClient: httpClient, + }, nil } var ( - plog log.Logger - HttpClient *http.Client + plog log.Logger ) func init() { plog = log.New("tsdb.opentsdb") tsdb.RegisterExecutor("opentsdb", NewOpenTsdbExecutor) - - HttpClient = tsdb.GetDefaultClient() } func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, queryContext *tsdb.QueryContext) *tsdb.BatchResult { @@ -64,7 +72,7 @@ func (e *OpenTsdbExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, return result } - res, err := ctxhttp.Do(ctx, HttpClient, req) + res, err := ctxhttp.Do(ctx, e.httpClient, req) if err != nil { result.Error = err return result diff --git a/pkg/tsdb/prometheus/prometheus.go b/pkg/tsdb/prometheus/prometheus.go index 21e1dfdef24..c391f00920a 100644 --- a/pkg/tsdb/prometheus/prometheus.go +++ b/pkg/tsdb/prometheus/prometheus.go @@ -9,18 +9,30 @@ import ( "gopkg.in/guregu/null.v3" + "net/http" + "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/tsdb" "github.com/prometheus/client_golang/api/prometheus" pmodel "github.com/prometheus/common/model" ) type PrometheusExecutor struct { - *tsdb.DataSourceInfo + *models.DataSource + Transport *http.Transport } -func NewPrometheusExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { - return &PrometheusExecutor{dsInfo} +func NewPrometheusExecutor(dsInfo *models.DataSource) (tsdb.Executor, error) { + transport, err := dsInfo.GetHttpTransport() + if err != nil { + return nil, err + } + + return &PrometheusExecutor{ + DataSource: dsInfo, + Transport: transport, + }, nil } var ( @@ -36,7 +48,8 @@ func init() { func (e *PrometheusExecutor) getClient() (prometheus.QueryAPI, error) { cfg := prometheus.Config{ - Address: e.DataSourceInfo.Url, + Address: e.DataSource.Url, + Transport: e.Transport, } client, err := prometheus.New(cfg) diff --git a/pkg/tsdb/testdata/testdata.go b/pkg/tsdb/testdata/testdata.go index cf2dcc0f898..6aefd8686d8 100644 --- a/pkg/tsdb/testdata/testdata.go +++ b/pkg/tsdb/testdata/testdata.go @@ -4,19 +4,20 @@ import ( "context" "github.com/grafana/grafana/pkg/log" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/tsdb" ) type TestDataExecutor struct { - *tsdb.DataSourceInfo + *models.DataSource log log.Logger } -func NewTestDataExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor { +func NewTestDataExecutor(dsInfo *models.DataSource) (tsdb.Executor, error) { return &TestDataExecutor{ - DataSourceInfo: dsInfo, - log: log.New("tsdb.testdata"), - } + DataSource: dsInfo, + log: log.New("tsdb.testdata"), + }, nil } func init() { diff --git a/pkg/tsdb/tsdb_test.go b/pkg/tsdb/tsdb_test.go index 998f59a6b9d..2b1a2372cd6 100644 --- a/pkg/tsdb/tsdb_test.go +++ b/pkg/tsdb/tsdb_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/grafana/grafana/pkg/models" . "github.com/smartystreets/goconvey/convey" ) @@ -15,9 +16,9 @@ func TestMetricQuery(t *testing.T) { Convey("Given 3 queries for 2 data sources", func() { request := &Request{ Queries: QuerySlice{ - {RefId: "A", DataSource: &DataSourceInfo{Id: 1}}, - {RefId: "B", DataSource: &DataSourceInfo{Id: 1}}, - {RefId: "C", DataSource: &DataSourceInfo{Id: 2}}, + {RefId: "A", DataSource: &models.DataSource{Id: 1}}, + {RefId: "B", DataSource: &models.DataSource{Id: 1}}, + {RefId: "C", DataSource: &models.DataSource{Id: 2}}, }, } @@ -32,9 +33,9 @@ func TestMetricQuery(t *testing.T) { Convey("Given query 2 depends on query 1", func() { request := &Request{ Queries: QuerySlice{ - {RefId: "A", DataSource: &DataSourceInfo{Id: 1}}, - {RefId: "B", DataSource: &DataSourceInfo{Id: 2}}, - {RefId: "C", DataSource: &DataSourceInfo{Id: 3}, Depends: []string{"A", "B"}}, + {RefId: "A", DataSource: &models.DataSource{Id: 1}}, + {RefId: "B", DataSource: &models.DataSource{Id: 2}}, + {RefId: "C", DataSource: &models.DataSource{Id: 3}, Depends: []string{"A", "B"}}, }, } @@ -56,7 +57,7 @@ func TestMetricQuery(t *testing.T) { Convey("When executing request with one query", t, func() { req := &Request{ Queries: QuerySlice{ - {RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, + {RefId: "A", DataSource: &models.DataSource{Id: 1, Type: "test"}}, }, } @@ -75,8 +76,8 @@ func TestMetricQuery(t *testing.T) { Convey("When executing one request with two queries from same data source", t, func() { req := &Request{ Queries: QuerySlice{ - {RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, - {RefId: "B", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, + {RefId: "A", DataSource: &models.DataSource{Id: 1, Type: "test"}}, + {RefId: "B", DataSource: &models.DataSource{Id: 1, Type: "test"}}, }, } @@ -101,9 +102,9 @@ func TestMetricQuery(t *testing.T) { Convey("When executing one request with three queries from different datasources", t, func() { req := &Request{ Queries: QuerySlice{ - {RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, - {RefId: "B", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}}, - {RefId: "C", DataSource: &DataSourceInfo{Id: 2, PluginId: "test"}}, + {RefId: "A", DataSource: &models.DataSource{Id: 1, Type: "test"}}, + {RefId: "B", DataSource: &models.DataSource{Id: 1, Type: "test"}}, + {RefId: "C", DataSource: &models.DataSource{Id: 2, Type: "test"}}, }, } @@ -118,7 +119,7 @@ func TestMetricQuery(t *testing.T) { Convey("When query uses data source of unknown type", t, func() { req := &Request{ Queries: QuerySlice{ - {RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "asdasdas"}}, + {RefId: "A", DataSource: &models.DataSource{Id: 1, Type: "asdasdas"}}, }, } @@ -130,10 +131,10 @@ func TestMetricQuery(t *testing.T) { req := &Request{ Queries: QuerySlice{ { - RefId: "A", DataSource: &DataSourceInfo{Id: 1, PluginId: "test"}, + RefId: "A", DataSource: &models.DataSource{Id: 1, Type: "test"}, }, { - RefId: "B", DataSource: &DataSourceInfo{Id: 2, PluginId: "test"}, Depends: []string{"A"}, + RefId: "B", DataSource: &models.DataSource{Id: 2, Type: "test"}, Depends: []string{"A"}, }, }, } @@ -167,9 +168,9 @@ func TestMetricQuery(t *testing.T) { } func registerFakeExecutor() *FakeExecutor { - executor := NewFakeExecutor(nil) - RegisterExecutor("test", func(dsInfo *DataSourceInfo) Executor { - return executor + executor, _ := NewFakeExecutor(nil) + RegisterExecutor("test", func(dsInfo *models.DataSource) (Executor, error) { + return executor, nil }) return executor