Use HTTP auth in blackbox exporter (#173)
authorConor Broderick <conor.broderick@robustperception.io>
Thu, 29 Jun 2017 10:57:16 +0000 (11:57 +0100)
committerBrian Brazil <brian.brazil@robustperception.io>
Thu, 29 Jun 2017 10:57:16 +0000 (11:57 +0100)
README.md
http.go
http_test.go
main.go

index 9ac3060df0b9120293e99ebbadf702c114dc3fe6..f11385364e9dfa98fbdf6d7b05313376fce8867b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -54,6 +54,16 @@ modules:
       headers:
         Content-Type: application/json
       body: '{}'
+  http_basic_auth_example:
+    prober: http
+    timeout: 5s
+    http:
+      method: POST
+      headers:
+        Host: "login.example.com"
+      basic_auth:
+        username: "username"
+        password: "mysecret"
   tcp_connect_example:
     prober: tcp
     timeout: 5s
diff --git a/http.go b/http.go
index d21be60aa53f4afe0d0d6151c2a72a3bd2014e25..cb9128877c9939463b1c42b8e61d5c4d47bf4a9e 100644 (file)
--- a/http.go
+++ b/http.go
@@ -59,7 +59,6 @@ func matchRegularExpressions(reader io.Reader, httpConfig HTTPProbe) bool {
 
 func probeHTTP(target string, module Module, registry *prometheus.Registry) (success bool) {
        var redirects int
-       var dialProtocol string
 
        var (
                contentLengthGauge = prometheus.NewGauge(prometheus.GaugeOpts{
@@ -114,30 +113,14 @@ func probeHTTP(target string, module Module, registry *prometheus.Registry) (suc
                return false
        }
 
-       if ip.IP.To4() == nil {
-               dialProtocol = "tcp6"
-       } else {
-               dialProtocol = "tcp4"
-       }
-
-       client := &http.Client{
-               Timeout: module.Timeout,
-       }
+       httpClientConfig := &module.HTTP.HTTPClientConfig
 
-       tlsconfig, err := config.NewTLSConfig(&module.HTTP.TLSConfig)
+       client, err := config.NewHTTPClientFromConfig(httpClientConfig)
        if err != nil {
-               log.Errorf("Error generating TLS config: %s", err)
+               log.Errorf("Error generating HTTP client: %v", err)
                return false
        }
-       dial := func(network, address string) (net.Conn, error) {
-               return net.Dial(dialProtocol, address)
-       }
-       client.Transport = &http.Transport{
-               TLSClientConfig:   tlsconfig,
-               Dial:              dial,
-               Proxy:             http.ProxyFromEnvironment,
-               DisableKeepAlives: true,
-       }
+       client.Timeout = module.Timeout
 
        client.CheckRedirect = func(_ *http.Request, via []*http.Request) error {
                redirects = len(via)
index bb8063a7f0ee8411826379ab2865761d08b4360b..976a30077cf76d30973d8832f561639fd5dee598 100644 (file)
@@ -121,6 +121,45 @@ func TestPost(t *testing.T) {
        }
 }
 
+func TestBasicAuth(t *testing.T) {
+       ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+       }))
+       defer ts.Close()
+
+       recorder := httptest.NewRecorder()
+       registry := prometheus.NewRegistry()
+       result := probeHTTP(ts.URL,
+               Module{Timeout: time.Second, HTTP: HTTPProbe{
+                       HTTPClientConfig: config.HTTPClientConfig{
+                               TLSConfig: config.TLSConfig{InsecureSkipVerify: false},
+                               BasicAuth: &config.BasicAuth{Username: "username", Password: "password"},
+                       },
+               }}, registry)
+       body := recorder.Body.String()
+       if !result {
+               t.Fatalf("HTTP probe failed, got %s", body)
+       }
+}
+
+func TestBearerToken(t *testing.T) {
+       ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+       }))
+       defer ts.Close()
+
+       recorder := httptest.NewRecorder()
+       registry := prometheus.NewRegistry()
+       result := probeHTTP(ts.URL,
+               Module{Timeout: time.Second, HTTP: HTTPProbe{
+                       HTTPClientConfig: config.HTTPClientConfig{
+                               BearerToken: config.Secret("mysecret"),
+                       },
+               }}, registry)
+       body := recorder.Body.String()
+       if !result {
+               t.Fatalf("HTTP probe failed, got %s", body)
+       }
+}
+
 func TestFailIfNotSSL(t *testing.T) {
        ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        }))
@@ -303,7 +342,9 @@ func TestFailIfSelfSignedCA(t *testing.T) {
        registry := prometheus.NewRegistry()
        result := probeHTTP(ts.URL,
                Module{Timeout: time.Second, HTTP: HTTPProbe{
-                       TLSConfig: config.TLSConfig{InsecureSkipVerify: false},
+                       HTTPClientConfig: config.HTTPClientConfig{
+                               TLSConfig: config.TLSConfig{InsecureSkipVerify: false},
+                       },
                }}, registry)
        body := recorder.Body.String()
        if result {
@@ -328,7 +369,9 @@ func TestSucceedIfSelfSignedCA(t *testing.T) {
        registry := prometheus.NewRegistry()
        result := probeHTTP(ts.URL,
                Module{Timeout: time.Second, HTTP: HTTPProbe{
-                       TLSConfig: config.TLSConfig{InsecureSkipVerify: true},
+                       HTTPClientConfig: config.HTTPClientConfig{
+                               TLSConfig: config.TLSConfig{InsecureSkipVerify: true},
+                       },
                }}, registry)
        body := recorder.Body.String()
        if !result {
@@ -353,7 +396,9 @@ func TestTLSConfigIsIgnoredForPlainHTTP(t *testing.T) {
        registry := prometheus.NewRegistry()
        result := probeHTTP(ts.URL,
                Module{Timeout: time.Second, HTTP: HTTPProbe{
-                       TLSConfig: config.TLSConfig{InsecureSkipVerify: false},
+                       HTTPClientConfig: config.HTTPClientConfig{
+                               TLSConfig: config.TLSConfig{InsecureSkipVerify: false},
+                       },
                }}, registry)
        body := recorder.Body.String()
        if !result {
diff --git a/main.go b/main.go
index 09c004b8ad107b2cce1cb9791a629f187cc5da1c..b6dc8ff6d2f92006f06f94700977f7c88a3cc505 100644 (file)
--- a/main.go
+++ b/main.go
@@ -54,17 +54,17 @@ type Module struct {
 
 type HTTPProbe struct {
        // Defaults to 2xx.
-       ValidStatusCodes       []int             `yaml:"valid_status_codes"`
-       PreferredIPProtocol    string            `yaml:"preferred_ip_protocol"`
-       NoFollowRedirects      bool              `yaml:"no_follow_redirects"`
-       FailIfSSL              bool              `yaml:"fail_if_ssl"`
-       FailIfNotSSL           bool              `yaml:"fail_if_not_ssl"`
-       Method                 string            `yaml:"method"`
-       Headers                map[string]string `yaml:"headers"`
-       FailIfMatchesRegexp    []string          `yaml:"fail_if_matches_regexp"`
-       FailIfNotMatchesRegexp []string          `yaml:"fail_if_not_matches_regexp"`
-       TLSConfig              config.TLSConfig  `yaml:"tls_config"`
-       Body                   string            `yaml:"body"`
+       ValidStatusCodes       []int                   `yaml:"valid_status_codes"`
+       PreferredIPProtocol    string                  `yaml:"preferred_ip_protocol"`
+       NoFollowRedirects      bool                    `yaml:"no_follow_redirects"`
+       FailIfSSL              bool                    `yaml:"fail_if_ssl"`
+       FailIfNotSSL           bool                    `yaml:"fail_if_not_ssl"`
+       Method                 string                  `yaml:"method"`
+       Headers                map[string]string       `yaml:"headers"`
+       FailIfMatchesRegexp    []string                `yaml:"fail_if_matches_regexp"`
+       FailIfNotMatchesRegexp []string                `yaml:"fail_if_not_matches_regexp"`
+       Body                   string                  `yaml:"body"`
+       HTTPClientConfig       config.HTTPClientConfig `yaml:"http_client_config,inline"`
 }
 
 type QueryResponse struct {