浏览代码

Add transport cache for reverse proxy (#6776)

* Add transport cache for reverse proxy
* Use updated at in cache
stuart nelson 9 年之前
父节点
当前提交
9ed21c6a16
共有 2 个文件被更改,包括 92 次插入13 次删除
  1. 29 0
      pkg/api/dataproxy.go
  2. 63 13
      pkg/api/dataproxy_test.go

+ 29 - 0
pkg/api/dataproxy.go

@@ -7,6 +7,7 @@ import (
 	"net/http"
 	"net/http/httputil"
 	"net/url"
+	"sync"
 	"time"
 
 	"github.com/grafana/grafana/pkg/api/cloudwatch"
@@ -18,7 +19,29 @@ 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,
@@ -56,6 +79,12 @@ func DataProxyTransport(ds *m.DataSource) (*http.Transport, error) {
 		}
 		transport.TLSClientConfig.Certificates = []tls.Certificate{cert}
 	}
+
+	ptc.cache[ds.Id] = cachedTransport{
+		Transport: transport,
+		updated:   ds.Updated,
+	}
+
 	return transport, nil
 }
 

+ 63 - 13
pkg/api/dataproxy_test.go

@@ -4,6 +4,7 @@ import (
 	"net/http"
 	"net/url"
 	"testing"
+	"time"
 
 	. "github.com/smartystreets/goconvey/convey"
 
@@ -16,6 +17,7 @@ import (
 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)
@@ -38,6 +40,7 @@ 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",
@@ -65,38 +68,85 @@ 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() {
+		clearCache()
 		setting.SecretKey = "password"
 
 		json := simplejson.New()
 		json.Set("tlsAuth", true)
 		json.Set("tlsAuthWithCACert", true)
+
+		t := time.Now()
 		ds := m.DataSource{
-			Url:      "htttp://k8s:8001",
-			Type:     "Kubernetes",
-			JsonData: json,
-			SecureJsonData: map[string][]byte{
-				"tlsCACert":     util.Encrypt([]byte(caCert), "password"),
-				"tlsClientCert": util.Encrypt([]byte(clientCert), "password"),
-				"tlsClientKey":  util.Encrypt([]byte(clientKey), "password"),
-			},
+			Url:     "http://k8s:8001",
+			Type:    "Kubernetes",
+			Updated: t.Add(-2 * time.Minute),
 		}
-		targetUrl, err := url.Parse(ds.Url)
-		proxy := NewReverseProxy(&ds, "", targetUrl)
-		proxy.Transport, err = DataProxyTransport(&ds)
+
+		transport, err := DataProxyTransport(&ds)
 		So(err, ShouldBeNil)
 
-		transport, ok := proxy.Transport.(*http.Transport)
+		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(ok, ShouldBeTrue)
 			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