The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/pkg/api/dataproxy.go

100 lines
2.8 KiB

package api
import (
"crypto/tls"
"net"
"net/http"
"net/http/httputil"
"net/url"
"time"
"github.com/grafana/grafana/pkg/api/cloudwatch"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
var dataProxyTransport = &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,
}
func NewReverseProxy(ds *m.DataSource, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy {
director := func(req *http.Request) {
req.URL.Scheme = targetUrl.Scheme
req.URL.Host = targetUrl.Host
req.Host = targetUrl.Host
reqQueryVals := req.URL.Query()
if ds.Type == m.DS_INFLUXDB_08 {
req.URL.Path = util.JoinUrlFragments(targetUrl.Path, "db/"+ds.Database+"/"+proxyPath)
reqQueryVals.Add("u", ds.User)
reqQueryVals.Add("p", ds.Password)
req.URL.RawQuery = reqQueryVals.Encode()
} else if ds.Type == m.DS_INFLUXDB {
req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)
req.URL.RawQuery = reqQueryVals.Encode()
if !ds.BasicAuth {
req.Header.Del("Authorization")
req.Header.Add("Authorization", util.GetBasicAuthHeader(ds.User, ds.Password))
}
} else {
req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath)
}
if ds.BasicAuth {
req.Header.Del("Authorization")
req.Header.Add("Authorization", util.GetBasicAuthHeader(ds.BasicAuthUser, ds.BasicAuthPassword))
}
// clear cookie headers
req.Header.Del("Cookie")
req.Header.Del("Set-Cookie")
}
return &httputil.ReverseProxy{Director: director, FlushInterval: time.Millisecond * 200}
}
10 years ago
func getDatasource(id int64, orgId int64) (*m.DataSource, error) {
query := m.GetDataSourceByIdQuery{Id: id, OrgId: orgId}
if err := bus.Dispatch(&query); err != nil {
10 years ago
return nil, err
}
return &query.Result, nil
}
func ProxyDataSourceRequest(c *middleware.Context) {
ds, err := getDatasource(c.ParamsInt64(":id"), c.OrgId)
if err != nil {
c.JsonApiErr(500, "Unable to load datasource meta data", err)
return
}
targetUrl, _ := url.Parse(ds.Url)
if len(setting.DataProxyWhiteList) > 0 {
if _, exists := setting.DataProxyWhiteList[targetUrl.Host]; !exists {
c.JsonApiErr(403, "Data proxy hostname and ip are not included in whitelist", nil)
return
}
}
10 years ago
if ds.Type == m.DS_CLOUDWATCH {
cloudwatch.HandleRequest(c, ds)
} else {
proxyPath := c.Params("*")
10 years ago
proxy := NewReverseProxy(ds, proxyPath, targetUrl)
proxy.Transport = dataProxyTransport
proxy.ServeHTTP(c.Resp, c.Req.Request)
c.Resp.Header().Del("Set-Cookie")
}
}