Commit 9ed21c6a by stuart nelson Committed by Carl Bergquist

Add transport cache for reverse proxy (#6776)

* Add transport cache for reverse proxy
* Use updated at in cache
parent 158656f5
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
"net/url" "net/url"
"sync"
"time" "time"
"github.com/grafana/grafana/pkg/api/cloudwatch" "github.com/grafana/grafana/pkg/api/cloudwatch"
...@@ -18,7 +19,29 @@ import ( ...@@ -18,7 +19,29 @@ import (
"github.com/grafana/grafana/pkg/util" "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) { 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{ transport := &http.Transport{
TLSClientConfig: &tls.Config{ TLSClientConfig: &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: true,
...@@ -56,6 +79,12 @@ func DataProxyTransport(ds *m.DataSource) (*http.Transport, error) { ...@@ -56,6 +79,12 @@ func DataProxyTransport(ds *m.DataSource) (*http.Transport, error) {
} }
transport.TLSClientConfig.Certificates = []tls.Certificate{cert} transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
} }
ptc.cache[ds.Id] = cachedTransport{
Transport: transport,
updated: ds.Updated,
}
return transport, nil return transport, nil
} }
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"testing" "testing"
"time"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
...@@ -16,6 +17,7 @@ import ( ...@@ -16,6 +17,7 @@ import (
func TestDataSourceProxy(t *testing.T) { func TestDataSourceProxy(t *testing.T) {
Convey("When getting graphite datasource proxy", t, func() { Convey("When getting graphite datasource proxy", t, func() {
clearCache()
ds := m.DataSource{Url: "htttp://graphite:8080", Type: m.DS_GRAPHITE} ds := m.DataSource{Url: "htttp://graphite:8080", Type: m.DS_GRAPHITE}
targetUrl, err := url.Parse(ds.Url) targetUrl, err := url.Parse(ds.Url)
proxy := NewReverseProxy(&ds, "/render", targetUrl) proxy := NewReverseProxy(&ds, "/render", targetUrl)
...@@ -38,6 +40,7 @@ func TestDataSourceProxy(t *testing.T) { ...@@ -38,6 +40,7 @@ func TestDataSourceProxy(t *testing.T) {
}) })
Convey("When getting influxdb datasource proxy", t, func() { Convey("When getting influxdb datasource proxy", t, func() {
clearCache()
ds := m.DataSource{ ds := m.DataSource{
Type: m.DS_INFLUXDB_08, Type: m.DS_INFLUXDB_08,
Url: "http://influxdb:8083", Url: "http://influxdb:8083",
...@@ -65,36 +68,83 @@ func TestDataSourceProxy(t *testing.T) { ...@@ -65,36 +68,83 @@ func TestDataSourceProxy(t *testing.T) {
}) })
}) })
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() { Convey("When getting kubernetes datasource proxy", t, func() {
clearCache()
setting.SecretKey = "password" setting.SecretKey = "password"
json := simplejson.New() json := simplejson.New()
json.Set("tlsAuth", true) json.Set("tlsAuth", true)
json.Set("tlsAuthWithCACert", true) json.Set("tlsAuthWithCACert", true)
t := time.Now()
ds := m.DataSource{ ds := m.DataSource{
Url: "htttp://k8s:8001", Url: "http://k8s:8001",
Type: "Kubernetes", Type: "Kubernetes",
JsonData: json, Updated: t.Add(-2 * time.Minute),
SecureJsonData: map[string][]byte{ }
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"), "tlsCACert": util.Encrypt([]byte(caCert), "password"),
"tlsClientCert": util.Encrypt([]byte(clientCert), "password"), "tlsClientCert": util.Encrypt([]byte(clientCert), "password"),
"tlsClientKey": util.Encrypt([]byte(clientKey), "password"), "tlsClientKey": util.Encrypt([]byte(clientKey), "password"),
},
} }
targetUrl, err := url.Parse(ds.Url) ds.Updated = t.Add(-1 * time.Minute)
proxy := NewReverseProxy(&ds, "", targetUrl)
proxy.Transport, err = DataProxyTransport(&ds)
So(err, ShouldBeNil)
transport, ok := proxy.Transport.(*http.Transport) transport, err = DataProxyTransport(&ds)
So(err, ShouldBeNil)
Convey("Should add cert", func() { Convey("Should add cert", func() {
So(ok, ShouldBeTrue)
So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false) So(transport.TLSClientConfig.InsecureSkipVerify, ShouldEqual, false)
So(len(transport.TLSClientConfig.Certificates), ShouldEqual, 1) 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----- const caCert string = `-----BEGIN CERTIFICATE-----
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment