diff --git a/config/config.go b/config/config.go index 136a4f898..1c5970092 100644 --- a/config/config.go +++ b/config/config.go @@ -100,6 +100,34 @@ var ( } ) +// This custom URL type allows validating at configuration load time. +type URL struct { + *url.URL +} + +// UnmarshalYAML implements the yaml.Unmarshaler interface for URLs. +func (u *URL) UnmarshalYAML(unmarshal func(interface{}) error) error { + var s string + if err := unmarshal(&s); err != nil { + return err + } + + urlp, err := url.Parse(s) + if err != nil { + return err + } + u.URL = urlp + return nil +} + +// MarshalYAML implements the yaml.Marshaler interface for URLs. +func (u URL) MarshalYAML() (interface{}, error) { + if u.URL != nil { + return u.String(), nil + } + return nil, nil +} + // Config is the top-level configuration for Prometheus's config files. type Config struct { GlobalConfig GlobalConfig `yaml:"global"` @@ -237,6 +265,8 @@ type ScrapeConfig struct { CACert string `yaml:"ca_cert,omitempty"` // The client cert authentication credentials for the targets. ClientCert *ClientCert `yaml:"client_cert,omitempty"` + // HTTP proxy server to use to connect to the targets. + ProxyURL URL `yaml:"proxy_url,omitempty"` // List of labeled target groups for this job. TargetGroups []*TargetGroup `yaml:"target_groups,omitempty"` diff --git a/notification/notification.go b/notification/notification.go index 38574e332..ff7fbd8e5 100644 --- a/notification/notification.go +++ b/notification/notification.go @@ -103,7 +103,7 @@ func NewNotificationHandler(o *NotificationHandlerOptions) *NotificationHandler alertmanagerURL: strings.TrimRight(o.AlertmanagerURL, "/"), pendingNotifications: make(chan NotificationReqs, o.QueueCapacity), - httpClient: httputil.NewDeadlineClient(o.Deadline), + httpClient: httputil.NewDeadlineClient(o.Deadline, nil), notificationLatency: prometheus.NewSummary(prometheus.SummaryOpts{ Namespace: namespace, diff --git a/retrieval/target.go b/retrieval/target.go index 67d14b389..b87d1b197 100644 --- a/retrieval/target.go +++ b/retrieval/target.go @@ -272,7 +272,7 @@ func newHTTPClient(cfg *config.ScrapeConfig) (*http.Client, error) { tlsConfig.BuildNameToCertificate() // Get a default roundtripper with the scrape timeout. - rt := httputil.NewDeadlineRoundTripper(time.Duration(cfg.ScrapeTimeout)) + rt := httputil.NewDeadlineRoundTripper(time.Duration(cfg.ScrapeTimeout), cfg.ProxyURL.URL) tr := rt.(*http.Transport) // Set the TLS config from above tr.TLSClientConfig = tlsConfig diff --git a/retrieval/target_test.go b/retrieval/target_test.go index 69a6e390c..95f327a62 100644 --- a/retrieval/target_test.go +++ b/retrieval/target_test.go @@ -447,7 +447,7 @@ func newTestTarget(targetURL string, deadline time.Duration, baseLabels clientmo deadline: deadline, status: &TargetStatus{}, scrapeInterval: 1 * time.Millisecond, - httpClient: httputil.NewDeadlineClient(deadline), + httpClient: httputil.NewDeadlineClient(deadline, nil), scraperStopping: make(chan struct{}), scraperStopped: make(chan struct{}), } diff --git a/storage/remote/influxdb/client.go b/storage/remote/influxdb/client.go index 570a32546..3e2be30ea 100644 --- a/storage/remote/influxdb/client.go +++ b/storage/remote/influxdb/client.go @@ -47,7 +47,7 @@ type Client struct { func NewClient(url string, timeout time.Duration, database, retentionPolicy string) *Client { return &Client{ url: url, - httpClient: httputil.NewDeadlineClient(timeout), + httpClient: httputil.NewDeadlineClient(timeout, nil), retentionPolicy: retentionPolicy, database: database, } diff --git a/storage/remote/opentsdb/client.go b/storage/remote/opentsdb/client.go index d6a3f53ec..5811c6280 100644 --- a/storage/remote/opentsdb/client.go +++ b/storage/remote/opentsdb/client.go @@ -50,7 +50,7 @@ type Client struct { func NewClient(url string, timeout time.Duration) *Client { return &Client{ url: url, - httpClient: httputil.NewDeadlineClient(timeout), + httpClient: httputil.NewDeadlineClient(timeout, nil), } } diff --git a/util/httputil/client.go b/util/httputil/client.go index 8311d184b..7703e311f 100644 --- a/util/httputil/client.go +++ b/util/httputil/client.go @@ -16,6 +16,7 @@ package httputil import ( "net" "net/http" + "net/url" "time" ) @@ -26,14 +27,16 @@ func NewClient(rt http.RoundTripper) *http.Client { // NewDeadlineClient returns a new http.Client which will time out long running // requests. -func NewDeadlineClient(timeout time.Duration) *http.Client { - return NewClient(NewDeadlineRoundTripper(timeout)) +func NewDeadlineClient(timeout time.Duration, proxyURL *url.URL) *http.Client { + return NewClient(NewDeadlineRoundTripper(timeout, proxyURL)) } // NewDeadlineRoundTripper returns a new http.RoundTripper which will time out // long running requests. -func NewDeadlineRoundTripper(timeout time.Duration) http.RoundTripper { +func NewDeadlineRoundTripper(timeout time.Duration, proxyURL *url.URL) http.RoundTripper { return &http.Transport{ + // Set proxy (if null, then becomes a direct connection) + Proxy: http.ProxyURL(proxyURL), // We need to disable keepalive, because we set a deadline on the // underlying connection. DisableKeepAlives: true,