"crypto/tls"
"errors"
"fmt"
+ "io"
+ "io/ioutil"
"net/http"
+ "regexp"
"strings"
"time"
"github.com/prometheus/log"
)
+func matchRegularExpressions(reader io.Reader, config HTTPProbe) bool {
+ body, err := ioutil.ReadAll(reader)
+ if err != nil {
+ log.Errorf("Error reading HTTP body: %s", err)
+ return false
+ }
+ for _, expression := range config.FailIfMatchesRegexp {
+ re, err := regexp.Compile(expression)
+ if err != nil {
+ log.Errorf("Could not compile expression %q as regular expression: %s", expression, err)
+ return false
+ }
+ if re.Match(body) {
+ return false
+ }
+ }
+ for _, expression := range config.FailIfNotMatchesRegexp {
+ re, err := regexp.Compile(expression)
+ if err != nil {
+ log.Errorf("Could not compile expression %q as regular expression: %s", expression, err)
+ return false
+ }
+ if !re.Match(body) {
+ return false
+ }
+ }
+ return true
+}
+
func getEarliestCertExpiry(state *tls.ConnectionState) time.Time {
earliest := time.Time{}
for _, cert := range state.PeerCertificates {
} else if 200 <= resp.StatusCode && resp.StatusCode < 300 {
success = true
}
+
+ if success && (len(config.FailIfMatchesRegexp) > 0 || len(config.FailIfNotMatchesRegexp) > 0) {
+ success = matchRegularExpressions(resp.Body, config)
+ }
}
if resp == nil {
package main
import (
+ "fmt"
"net/http"
"net/http/httptest"
"strings"
t.Fatalf("Expected HTTP without SSL, got %s", body)
}
}
+
+func TestFailIfMatchesRegexp(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Bad news: could not connect to database server")
+ }))
+ defer ts.Close()
+
+ recorder := httptest.NewRecorder()
+ result := probeHTTP(ts.URL, recorder,
+ Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database"}}})
+ body := recorder.Body.String()
+ if result {
+ t.Fatalf("Regexp test succeeded unexpectedly, got %s", body)
+ }
+
+ ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Download the latest version here")
+ }))
+ defer ts.Close()
+
+ recorder = httptest.NewRecorder()
+ result = probeHTTP(ts.URL, recorder,
+ Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database"}}})
+ body = recorder.Body.String()
+ if !result {
+ t.Fatalf("Regexp test failed unexpectedly, got %s", body)
+ }
+
+ // With multiple regexps configured, verify that any matching regexp causes
+ // the probe to fail, but probes succeed when no regexp matches.
+ ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "internal error")
+ }))
+ defer ts.Close()
+
+ recorder = httptest.NewRecorder()
+ result = probeHTTP(ts.URL, recorder,
+ Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}})
+ body = recorder.Body.String()
+ if result {
+ t.Fatalf("Regexp test succeeded unexpectedly, got %s", body)
+ }
+
+ ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "hello world")
+ }))
+ defer ts.Close()
+
+ recorder = httptest.NewRecorder()
+ result = probeHTTP(ts.URL, recorder,
+ Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}})
+ body = recorder.Body.String()
+ if !result {
+ t.Fatalf("Regexp test failed unexpectedly, got %s", body)
+ }
+}
+
+func TestFailIfNotMatchesRegexp(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Bad news: could not connect to database server")
+ }))
+ defer ts.Close()
+
+ recorder := httptest.NewRecorder()
+ result := probeHTTP(ts.URL, recorder,
+ Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here"}}})
+ body := recorder.Body.String()
+ if result {
+ t.Fatalf("Regexp test succeeded unexpectedly, got %s", body)
+ }
+
+ ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Download the latest version here")
+ }))
+ defer ts.Close()
+
+ recorder = httptest.NewRecorder()
+ result = probeHTTP(ts.URL, recorder,
+ Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here"}}})
+ body = recorder.Body.String()
+ if !result {
+ t.Fatalf("Regexp test failed unexpectedly, got %s", body)
+ }
+
+ // With multiple regexps configured, verify that any non-matching regexp
+ // causes the probe to fail, but probes succeed when all regexps match.
+ ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Download the latest version here")
+ }))
+ defer ts.Close()
+
+ recorder = httptest.NewRecorder()
+ result = probeHTTP(ts.URL, recorder,
+ Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}})
+ body = recorder.Body.String()
+ if result {
+ t.Fatalf("Regexp test succeeded unexpectedly, got %s", body)
+ }
+
+ ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Download the latest version here. Copyright 2015 Test Inc.")
+ }))
+ defer ts.Close()
+
+ recorder = httptest.NewRecorder()
+ result = probeHTTP(ts.URL, recorder,
+ Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}})
+ body = recorder.Body.String()
+ if !result {
+ t.Fatalf("Regexp test failed unexpectedly, got %s", body)
+ }
+}