Files
grafana/pkg/infra/httpclient/httpclientprovider/http_client_provider.go
beejeebus 8f79e4882f Replace usage of http.DefaultClient and http.DefaultTransport (#104135)
Remove usage of http.DefaultClient and http.DefaultTransport

Part of grafana/data-sources#484
2025-05-09 13:26:39 -04:00

111 lines
4.0 KiB
Go

package httpclientprovider
import (
"net/http"
"time"
"github.com/grafana/grafana-aws-sdk/pkg/awsds"
awssdk "github.com/grafana/grafana-aws-sdk/pkg/sigv4"
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/mwitkow/go-conntrack"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics/metricutil"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/setting"
)
var newProviderFunc = sdkhttpclient.NewProvider
// New creates a new HTTP client provider with pre-configured middlewares.
func New(cfg *setting.Cfg, validator validations.DataSourceRequestURLValidator, tracer tracing.Tracer) *sdkhttpclient.Provider {
logger := log.New("httpclient")
middlewares := []sdkhttpclient.Middleware{
TracingMiddleware(logger, tracer),
DataSourceMetricsMiddleware(),
sdkhttpclient.ContextualMiddleware(),
SetUserAgentMiddleware(cfg.DataProxyUserAgent),
sdkhttpclient.BasicAuthenticationMiddleware(),
sdkhttpclient.CustomHeadersMiddleware(),
sdkhttpclient.ResponseLimitMiddleware(cfg.ResponseLimit),
RedirectLimitMiddleware(validator),
}
if httpLoggingEnabled(cfg.PluginSettings) {
middlewares = append(middlewares, HTTPLoggerMiddleware(cfg.PluginSettings))
}
if cfg.IPRangeACEnabled {
middlewares = append(middlewares, GrafanaRequestIDHeaderMiddleware(cfg, logger))
}
middlewares = append(middlewares, sdkhttpclient.ErrorSourceMiddleware())
// SigV4 signing should be performed after all headers are added
if cfg.SigV4AuthEnabled {
authSettings := awsds.AuthSettings{
AllowedAuthProviders: cfg.AWSAllowedAuthProviders,
AssumeRoleEnabled: cfg.AWSAssumeRoleEnabled,
ExternalID: cfg.AWSExternalId,
ListMetricsPageLimit: cfg.AWSListMetricsPageLimit,
SecureSocksDSProxyEnabled: cfg.SecureSocksDSProxy.Enabled,
}
if cfg.AWSSessionDuration != "" {
sessionDuration, err := gtime.ParseDuration(cfg.AWSSessionDuration)
if err == nil {
authSettings.SessionDuration = &sessionDuration
}
}
middlewares = append(middlewares, awssdk.SigV4MiddlewareWithAuthSettings(cfg.SigV4VerboseLogging, authSettings))
}
setDefaultTimeoutOptions(cfg)
return newProviderFunc(sdkhttpclient.ProviderOptions{
Middlewares: middlewares,
ConfigureTransport: func(opts sdkhttpclient.Options, transport *http.Transport) {
datasourceName, exists := opts.Labels["datasource_name"]
if !exists {
return
}
datasourceLabelName, err := metricutil.SanitizeLabelName(datasourceName)
if err != nil {
return
}
newConntrackRoundTripper(datasourceLabelName, transport)
},
})
}
// newConntrackRoundTripper takes a http.Transport and adds the Conntrack Dialer
// so we can instrument outbound connections
func newConntrackRoundTripper(name string, transport *http.Transport) *http.Transport {
transport.DialContext = conntrack.NewDialContextFunc(
conntrack.DialWithName(name),
conntrack.DialWithDialContextFunc(transport.DialContext),
)
return transport
}
// setDefaultTimeoutOptions overrides the default timeout options for the SDK.
//
// Note: Not optimal changing global state, but hard to not do in this case.
func setDefaultTimeoutOptions(cfg *setting.Cfg) {
sdkhttpclient.DefaultTimeoutOptions = sdkhttpclient.TimeoutOptions{
Timeout: time.Duration(cfg.DataProxyTimeout) * time.Second,
DialTimeout: time.Duration(cfg.DataProxyDialTimeout) * time.Second,
KeepAlive: time.Duration(cfg.DataProxyKeepAlive) * time.Second,
TLSHandshakeTimeout: time.Duration(cfg.DataProxyTLSHandshakeTimeout) * time.Second,
ExpectContinueTimeout: time.Duration(cfg.DataProxyExpectContinueTimeout) * time.Second,
MaxConnsPerHost: cfg.DataProxyMaxConnsPerHost,
MaxIdleConns: cfg.DataProxyMaxIdleConns,
MaxIdleConnsPerHost: cfg.DataProxyMaxIdleConns,
IdleConnTimeout: time.Duration(cfg.DataProxyIdleConnTimeout) * time.Second,
}
}