-package main
+package config
import (
"errors"
"fmt"
+ "io/ioutil"
"strings"
"sync"
"time"
+ yaml "gopkg.in/yaml.v2"
+
"github.com/prometheus/common/config"
)
C *Config
}
+func (sc *SafeConfig) ReloadConfig(confFile string) (err error) {
+ var c = &Config{}
+
+ yamlFile, err := ioutil.ReadFile(confFile)
+ if err != nil {
+ return fmt.Errorf("Error reading config file: %s", err)
+ }
+
+ if err := yaml.Unmarshal(yamlFile, c); err != nil {
+ return fmt.Errorf("Error parsing config file: %s", err)
+ }
+
+ sc.Lock()
+ sc.C = c
+ sc.Unlock()
+
+ return nil
+}
+
type Module struct {
Prober string `yaml:"prober,omitempty"`
Timeout time.Duration `yaml:"timeout,omitempty"`
-package main
+package config
import (
"strings"
C: &Config{},
}
- err := sc.reloadConfig("testdata/blackbox-good.yml")
+ err := sc.ReloadConfig("testdata/blackbox-good.yml")
if err != nil {
t.Errorf("Error loading config %v: %v", "blackbox.yml", err)
}
}{
{
ConfigFile: "testdata/blackbox-bad.yml",
- ExpectedError: "unknown fields in dns probe: invalid_extra_field",
+ ExpectedError: "Error parsing config file: unknown fields in dns probe: invalid_extra_field",
},
{
ConfigFile: "testdata/invalid-dns-module.yml",
- ExpectedError: "Query name must be set for DNS module",
+ ExpectedError: "Error parsing config file: Query name must be set for DNS module",
},
}
for i, test := range tests {
- err := sc.reloadConfig(test.ConfigFile)
+ err := sc.ReloadConfig(test.ConfigFile)
if err.Error() != test.ExpectedError {
t.Errorf("In case %v:\nExpected:\n%v\nGot:\n%v", i, test.ExpectedError, err.Error())
}
C: &Config{},
}
- err := sc.reloadConfig("testdata/blackbox-good.yml")
+ err := sc.ReloadConfig("testdata/blackbox-good.yml")
if err != nil {
t.Errorf("Error loading config %v: %v", "testdata/blackbox-good.yml", err)
}
import (
"context"
"fmt"
- "io/ioutil"
"net/http"
"os"
"os/signal"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/log"
"github.com/prometheus/common/version"
+
+ "github.com/prometheus/blackbox_exporter/config"
+ "github.com/prometheus/blackbox_exporter/prober"
)
var (
- sc = &SafeConfig{
- C: &Config{},
+ sc = &config.SafeConfig{
+ C: &config.Config{},
}
configFile = kingpin.Flag("config.file", "Blackbox exporter configuration file.").Default("blackbox.yml").String()
listenAddress = kingpin.Flag("web.listen-address", "The address to listen on for HTTP requests.").Default(":9115").String()
timeoutOffset = kingpin.Flag("timeout-offset", "Offset to subtract from timeout in seconds.").Default("0.5").Float64()
-)
-
-var Probers = map[string]func(context.Context, string, Module, *prometheus.Registry) bool{
- "http": probeHTTP,
- "tcp": probeTCP,
- "icmp": probeICMP,
- "dns": probeDNS,
-}
-
-func (sc *SafeConfig) reloadConfig(confFile string) (err error) {
- var c = &Config{}
-
- yamlFile, err := ioutil.ReadFile(confFile)
- if err != nil {
- log.Errorf("Error reading config file: %s", err)
- return err
- }
- if err := yaml.Unmarshal(yamlFile, c); err != nil {
- log.Errorf("Error parsing config file: %s", err)
- return err
+ Probers = map[string]prober.ProbeFn{
+ "http": prober.ProbeHTTP,
+ "tcp": prober.ProbeTCP,
+ "icmp": prober.ProbeICMP,
+ "dns": prober.ProbeDNS,
}
+)
- sc.Lock()
- sc.C = c
- sc.Unlock()
-
- log.Infoln("Loaded config file")
- return nil
-}
-
-func probeHandler(w http.ResponseWriter, r *http.Request, c *Config) {
+func probeHandler(w http.ResponseWriter, r *http.Request, c *config.Config) {
moduleName := r.URL.Query().Get("module")
if moduleName == "" {
moduleName = "http_2xx"
log.Infoln("Starting blackbox_exporter", version.Info())
log.Infoln("Build context", version.BuildContext())
- if err := sc.reloadConfig(*configFile); err != nil {
+ if err := sc.ReloadConfig(*configFile); err != nil {
log.Fatalf("Error loading config: %s", err)
}
+ log.Infoln("Loaded config file")
hup := make(chan os.Signal)
reloadCh := make(chan chan error)
for {
select {
case <-hup:
- if err := sc.reloadConfig(*configFile); err != nil {
+ if err := sc.ReloadConfig(*configFile); err != nil {
log.Errorf("Error reloading config: %s", err)
+ continue
}
+ log.Infoln("Loaded config file")
case rc := <-reloadCh:
- if err := sc.reloadConfig(*configFile); err != nil {
+ if err := sc.ReloadConfig(*configFile); err != nil {
log.Errorf("Error reloading config: %s", err)
rc <- err
} else {
+ log.Infoln("Loaded config file")
rc <- nil
}
}
--- /dev/null
+package main
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+ "time"
+
+ "github.com/prometheus/blackbox_exporter/config"
+)
+
+var c = &config.Config{
+ Modules: map[string]config.Module{
+ "http_2xx": config.Module{
+ Prober: "http",
+ Timeout: 10 * time.Second,
+ },
+ },
+}
+
+func TestPrometheusTimeoutHTTP(t *testing.T) {
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ time.Sleep(2 * time.Second)
+ }))
+ defer ts.Close()
+
+ req, err := http.NewRequest("GET", "?target="+ts.URL, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Header.Set("X-Prometheus-Scrape-Timeout-Seconds", "1")
+
+ rr := httptest.NewRecorder()
+ handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ probeHandler(w, r, c)
+ })
+
+ handler.ServeHTTP(rr, req)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Errorf("probe request handler returned wrong status code: %v, want %v", status, http.StatusOK)
+ }
+}
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package prober
import (
"context"
"github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
+
+ "github.com/prometheus/blackbox_exporter/config"
)
// validRRs checks a slice of RRs received from the server against a DNSRRValidator.
-func validRRs(rrs *[]dns.RR, v *DNSRRValidator) bool {
+func validRRs(rrs *[]dns.RR, v *config.DNSRRValidator) bool {
// Fail the probe if there are no RRs of a given type, but a regexp match is required
// (i.e. FailIfNotMatchesRegexp is set).
if len(*rrs) == 0 && len(v.FailIfNotMatchesRegexp) > 0 {
return false
}
-func probeDNS(ctx context.Context, target string, module Module, registry *prometheus.Registry) bool {
+func ProbeDNS(ctx context.Context, target string, module config.Module, registry *prometheus.Registry) bool {
var numAnswer, numAuthority, numAdditional int
var dialProtocol string
probeDNSAnswerRRSGauge := prometheus.NewGauge(prometheus.GaugeOpts{
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package prober
import (
"context"
"github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
+
+ "github.com/prometheus/blackbox_exporter/config"
)
var PROTOCOLS = [...]string{"udp", "tcp"}
func TestRecursiveDNSResponse(t *testing.T) {
tests := []struct {
- Probe DNSProbe
+ Probe config.DNSProbe
ShouldSucceed bool
}{
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
}, true,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"},
}, false,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
- ValidateAnswer: DNSRRValidator{
+ ValidateAnswer: config.DNSRRValidator{
FailIfMatchesRegexp: []string{".*7200.*"},
FailIfNotMatchesRegexp: []string{".*3600.*"},
},
}, true,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
- ValidateAuthority: DNSRRValidator{
+ ValidateAuthority: config.DNSRRValidator{
FailIfMatchesRegexp: []string{".*7200.*"},
},
}, true,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
- ValidateAdditional: DNSRRValidator{
+ ValidateAdditional: config.DNSRRValidator{
FailIfNotMatchesRegexp: []string{".*3600.*"},
},
}, false,
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeDNS(testCTX, addr.String(), Module{Timeout: time.Second, DNS: test.Probe}, registry)
+ result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry)
if result != test.ShouldSucceed {
t.Fatalf("Test %d had unexpected result: %v", i, result)
}
func TestAuthoritativeDNSResponse(t *testing.T) {
tests := []struct {
- Probe DNSProbe
+ Probe config.DNSProbe
ShouldSucceed bool
}{
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
}, true,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"},
}, false,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
- ValidateAnswer: DNSRRValidator{
+ ValidateAnswer: config.DNSRRValidator{
FailIfMatchesRegexp: []string{".*3600.*"},
FailIfNotMatchesRegexp: []string{".*3600.*"},
},
}, false,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
- ValidateAnswer: DNSRRValidator{
+ ValidateAnswer: config.DNSRRValidator{
FailIfMatchesRegexp: []string{".*7200.*"},
FailIfNotMatchesRegexp: []string{".*7200.*"},
},
}, false,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
- ValidateAuthority: DNSRRValidator{
+ ValidateAuthority: config.DNSRRValidator{
FailIfNotMatchesRegexp: []string{"ns.*.isp.net"},
},
}, true,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
- ValidateAdditional: DNSRRValidator{
+ ValidateAdditional: config.DNSRRValidator{
FailIfNotMatchesRegexp: []string{"^ns.*.isp"},
},
}, true,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
- ValidateAdditional: DNSRRValidator{
+ ValidateAdditional: config.DNSRRValidator{
FailIfMatchesRegexp: []string{"^ns.*.isp"},
},
}, false,
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeDNS(testCTX, addr.String(), Module{Timeout: time.Second, DNS: test.Probe}, registry)
+ result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry)
if result != test.ShouldSucceed {
t.Fatalf("Test %d had unexpected result: %v", i, result)
}
func TestServfailDNSResponse(t *testing.T) {
tests := []struct {
- Probe DNSProbe
+ Probe config.DNSProbe
ShouldSucceed bool
}{
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
}, false,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"},
}, true,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
QueryType: "NOT_A_VALID_QUERY_TYPE",
}, false,
},
{
- DNSProbe{
+ config.DNSProbe{
QueryName: "example.com",
ValidRcodes: []string{"NOT_A_VALID_RCODE"},
}, false,
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeDNS(testCTX, addr.String(), Module{Timeout: time.Second, DNS: test.Probe}, registry)
+ result := ProbeDNS(testCTX, addr.String(), config.Module{Timeout: time.Second, DNS: test.Probe}, registry)
if result != test.ShouldSucceed {
t.Fatalf("Test %d had unexpected result: %v", i, result)
}
_, port, _ := net.SplitHostPort(addr.String())
// Force IPv4
- module := Module{
+ module := config.Module{
Timeout: time.Second,
- DNS: DNSProbe{
+ DNS: config.DNSProbe{
QueryName: "example.com",
TransportProtocol: protocol,
PreferredIPProtocol: "ip4",
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result := ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("DNS protocol: \"%v4\" connection test failed, expected success.", protocol)
}
checkRegistryResults(expectedResults, mfs, t)
// Force IPv6
- module = Module{
+ module = config.Module{
Timeout: time.Second,
- DNS: DNSProbe{
+ DNS: config.DNSProbe{
QueryName: "example.com",
TransportProtocol: protocol,
PreferredIPProtocol: "ip6",
registry = prometheus.NewRegistry()
testCTX, cancel = context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result = probeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("DNS protocol: \"%v6\" connection test failed, expected success.", protocol)
}
checkRegistryResults(expectedResults, mfs, t)
// Prefer IPv6
- module = Module{
+ module = config.Module{
Timeout: time.Second,
- DNS: DNSProbe{
+ DNS: config.DNSProbe{
QueryName: "example.com",
TransportProtocol: protocol,
PreferredIPProtocol: "ip6",
registry = prometheus.NewRegistry()
testCTX, cancel = context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result = probeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("DNS protocol: \"%v\", preferred \"ip6\" connection test failed, expected success.", protocol)
}
checkRegistryResults(expectedResults, mfs, t)
// Prefer IPv4
- module = Module{
+ module = config.Module{
Timeout: time.Second,
- DNS: DNSProbe{
+ DNS: config.DNSProbe{
QueryName: "example.com",
TransportProtocol: protocol,
PreferredIPProtocol: "ip4",
registry = prometheus.NewRegistry()
testCTX, cancel = context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result = probeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("DNS protocol: \"%v\", preferred \"ip4\" connection test failed, expected success.", protocol)
}
checkRegistryResults(expectedResults, mfs, t)
// Prefer none
- module = Module{
+ module = config.Module{
Timeout: time.Second,
- DNS: DNSProbe{
+ DNS: config.DNSProbe{
QueryName: "example.com",
TransportProtocol: protocol,
},
registry = prometheus.NewRegistry()
testCTX, cancel = context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result = probeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("DNS protocol: \"%v\" connection test failed, expected success.", protocol)
}
checkRegistryResults(expectedResults, mfs, t)
// No protocol
- module = Module{
+ module = config.Module{
Timeout: time.Second,
- DNS: DNSProbe{
+ DNS: config.DNSProbe{
QueryName: "example.com",
},
}
registry = prometheus.NewRegistry()
testCTX, cancel = context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result = probeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeDNS(testCTX, net.JoinHostPort("localhost", port), module, registry)
if protocol == "udp" {
if !result {
t.Fatalf("DNS test connection with protocol %s failed, expected success.", protocol)
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package prober
import (
"context"
"strings"
"github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/common/config"
+ pconfig "github.com/prometheus/common/config"
"github.com/prometheus/common/log"
+
+ "github.com/prometheus/blackbox_exporter/config"
)
-func matchRegularExpressions(reader io.Reader, httpConfig HTTPProbe) bool {
+func matchRegularExpressions(reader io.Reader, httpConfig config.HTTPProbe) bool {
body, err := ioutil.ReadAll(reader)
if err != nil {
log.Errorf("Error reading HTTP body: %s", err)
return true
}
-func probeHTTP(ctx context.Context, target string, module Module, registry *prometheus.Registry) (success bool) {
+func ProbeHTTP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry) (success bool) {
var redirects int
var (
contentLengthGauge = prometheus.NewGauge(prometheus.GaugeOpts{
httpClientConfig := &module.HTTP.HTTPClientConfig
- client, err := config.NewHTTPClientFromConfig(httpClientConfig)
+ client, err := pconfig.NewHTTPClientFromConfig(httpClientConfig)
if err != nil {
log.Errorf("Error generating HTTP client: %v", err)
return false
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package prober
import (
"context"
"time"
"github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/common/config"
+ pconfig "github.com/prometheus/common/config"
+
+ "github.com/prometheus/blackbox_exporter/config"
)
func TestHTTPStatusCodes(t *testing.T) {
recorder := httptest.NewRecorder()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{ValidStatusCodes: test.ValidStatusCodes}}, registry)
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ValidStatusCodes: test.ValidStatusCodes}}, registry)
body := recorder.Body.String()
if result != test.ShouldSucceed {
t.Fatalf("Test %d had unexpected result: %s", i, body)
defer ts.Close()
recorder := httptest.NewRecorder()
registry := prometheus.NewRegistry()
- result := probeHTTP(context.Background(), ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{
+ result := ProbeHTTP(context.Background(), ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{
ValidHTTPVersions: test.ValidHTTPVersions,
}}, registry)
body := recorder.Body.String()
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL, Module{Timeout: time.Second, HTTP: HTTPProbe{}}, registry)
+ result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{}}, registry)
body := recorder.Body.String()
if !result {
t.Fatalf("Redirect test failed unexpectedly, got %s", body)
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{NoFollowRedirects: true, ValidStatusCodes: []int{302}}}, registry)
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{NoFollowRedirects: true, ValidStatusCodes: []int{302}}}, registry)
body := recorder.Body.String()
if !result {
t.Fatalf("Redirect test failed unexpectedly, got %s", body)
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{Method: "POST"}}, registry)
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{Method: "POST"}}, registry)
body := recorder.Body.String()
if !result {
t.Fatalf("Post test failed unexpectedly, got %s", body)
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{
- HTTPClientConfig: config.HTTPClientConfig{
- TLSConfig: config.TLSConfig{InsecureSkipVerify: false},
- BasicAuth: &config.BasicAuth{Username: "username", Password: "password"},
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{
+ HTTPClientConfig: pconfig.HTTPClientConfig{
+ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false},
+ BasicAuth: &pconfig.BasicAuth{Username: "username", Password: "password"},
},
}}, registry)
body := recorder.Body.String()
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{
- HTTPClientConfig: config.HTTPClientConfig{
- BearerToken: config.Secret("mysecret"),
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{
+ HTTPClientConfig: pconfig.HTTPClientConfig{
+ BearerToken: pconfig.Secret("mysecret"),
},
}}, registry)
body := recorder.Body.String()
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotSSL: true}}, registry)
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotSSL: true}}, registry)
body := recorder.Body.String()
if result {
t.Fatalf("Fail if not SSL test suceeded unexpectedly, got %s", body)
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database"}}}, registry)
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database"}}}, registry)
body := recorder.Body.String()
if result {
t.Fatalf("Regexp test succeeded unexpectedly, got %s", body)
recorder = httptest.NewRecorder()
registry = prometheus.NewRegistry()
- result = probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database"}}}, registry)
+ result = ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database"}}}, registry)
body = recorder.Body.String()
if !result {
t.Fatalf("Regexp test failed unexpectedly, got %s", body)
recorder = httptest.NewRecorder()
registry = prometheus.NewRegistry()
- result = probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}}, registry)
+ result = ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}}, registry)
body = recorder.Body.String()
if result {
t.Fatalf("Regexp test succeeded unexpectedly, got %s", body)
recorder = httptest.NewRecorder()
registry = prometheus.NewRegistry()
- result = probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}}, registry)
+ result = ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}}, registry)
body = recorder.Body.String()
if !result {
t.Fatalf("Regexp test failed unexpectedly, got %s", body)
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here"}}}, registry)
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here"}}}, registry)
body := recorder.Body.String()
if result {
t.Fatalf("Regexp test succeeded unexpectedly, got %s", body)
recorder = httptest.NewRecorder()
registry = prometheus.NewRegistry()
- result = probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here"}}}, registry)
+ result = ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here"}}}, registry)
body = recorder.Body.String()
if !result {
t.Fatalf("Regexp test failed unexpectedly, got %s", body)
recorder = httptest.NewRecorder()
registry = prometheus.NewRegistry()
- result = probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}}, registry)
+ result = ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}}, registry)
body = recorder.Body.String()
if result {
t.Fatalf("Regexp test succeeded unexpectedly, got %s", body)
recorder = httptest.NewRecorder()
registry = prometheus.NewRegistry()
- result = probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}}, registry)
+ result = ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}}, registry)
body = recorder.Body.String()
if !result {
t.Fatalf("Regexp test failed unexpectedly, got %s", body)
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL, Module{Timeout: time.Second, HTTP: HTTPProbe{
+ result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{
Headers: headers,
}}, registry)
if !result {
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{
- HTTPClientConfig: config.HTTPClientConfig{
- TLSConfig: config.TLSConfig{InsecureSkipVerify: false},
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{
+ HTTPClientConfig: pconfig.HTTPClientConfig{
+ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false},
},
}}, registry)
body := recorder.Body.String()
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{
- HTTPClientConfig: config.HTTPClientConfig{
- TLSConfig: config.TLSConfig{InsecureSkipVerify: true},
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{
+ HTTPClientConfig: pconfig.HTTPClientConfig{
+ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true},
},
}}, registry)
body := recorder.Body.String()
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- result := probeHTTP(testCTX, ts.URL,
- Module{Timeout: time.Second, HTTP: HTTPProbe{
- HTTPClientConfig: config.HTTPClientConfig{
- TLSConfig: config.TLSConfig{InsecureSkipVerify: false},
+ result := ProbeHTTP(testCTX, ts.URL,
+ config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{
+ HTTPClientConfig: pconfig.HTTPClientConfig{
+ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false},
},
}}, registry)
body := recorder.Body.String()
}
checkRegistryResults(expectedResults, mfs, t)
}
-
-var c = &Config{
- Modules: map[string]Module{
- "http_2xx": Module{
- Prober: "http",
- Timeout: 10 * time.Second,
- },
- },
-}
-
-func TestPrometheusTimeoutHTTP(t *testing.T) {
-
- ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- time.Sleep(2 * time.Second)
- }))
- defer ts.Close()
-
- req, err := http.NewRequest("GET", "?target="+ts.URL, nil)
- if err != nil {
- t.Fatal(err)
- }
- req.Header.Set("X-Prometheus-Scrape-Timeout-Seconds", "1")
-
- rr := httptest.NewRecorder()
- handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- probeHandler(w, r, c)
- })
-
- handler.ServeHTTP(rr, req)
-
- if status := rr.Code; status != http.StatusOK {
- t.Errorf("probe request handler returned wrong status code: %v, want %v", status, http.StatusOK)
- }
-}
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package prober
import (
"bytes"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/log"
+
+ "github.com/prometheus/blackbox_exporter/config"
)
var (
return icmpSequence
}
-func probeICMP(ctx context.Context, target string, module Module, registry *prometheus.Registry) (success bool) {
+func ProbeICMP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry) (success bool) {
var (
socket *icmp.PacketConn
requestType icmp.Type
--- /dev/null
+package prober
+
+import (
+ "context"
+
+ "github.com/prometheus/client_golang/prometheus"
+
+ "github.com/prometheus/blackbox_exporter/config"
+)
+
+type ProbeFn func(ctx context.Context, target string, config config.Module, registry *prometheus.Registry) bool
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package prober
import (
"bufio"
"regexp"
"github.com/prometheus/client_golang/prometheus"
- "github.com/prometheus/common/config"
+ pconfig "github.com/prometheus/common/config"
"github.com/prometheus/common/log"
+
+ "github.com/prometheus/blackbox_exporter/config"
)
-func dialTCP(ctx context.Context, target string, module Module, registry *prometheus.Registry) (net.Conn, error) {
+func dialTCP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry) (net.Conn, error) {
var dialProtocol, dialTarget string
dialer := &net.Dialer{}
targetAddress, port, err := net.SplitHostPort(target)
if !module.TCP.TLS {
return dialer.DialContext(ctx, dialProtocol, dialTarget)
}
- tlsConfig, err := config.NewTLSConfig(&module.TCP.TLSConfig)
+ tlsConfig, err := pconfig.NewTLSConfig(&module.TCP.TLSConfig)
if err != nil {
log.Errorf("Error creating TLS configuration: %v", err)
return nil, err
return tls.DialWithDialer(dialer, dialProtocol, dialTarget, tlsConfig)
}
-func probeTCP(ctx context.Context, target string, module Module, registry *prometheus.Registry) bool {
+func ProbeTCP(ctx context.Context, target string, module config.Module, registry *prometheus.Registry) bool {
probeSSLEarliestCertExpiry := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "probe_ssl_earliest_cert_expiry",
Help: "Returns earliest SSL cert expiry date",
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package prober
import (
"context"
"time"
"github.com/prometheus/client_golang/prometheus"
+
+ "github.com/prometheus/blackbox_exporter/config"
)
func TestTCPConnection(t *testing.T) {
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
registry := prometheus.NewRegistry()
- if !probeTCP(testCTX, ln.Addr().String(), Module{}, registry) {
+ if !ProbeTCP(testCTX, ln.Addr().String(), config.Module{}, registry) {
t.Fatalf("TCP module failed, expected success.")
}
<-ch
registry := prometheus.NewRegistry()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- if probeTCP(testCTX, ":0", Module{}, registry) {
+ if ProbeTCP(testCTX, ":0", config.Module{}, registry) {
t.Fatalf("TCP module suceeded, expected failure.")
}
}
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
- module := Module{
- TCP: TCPProbe{
- QueryResponse: []QueryResponse{
+ module := config.Module{
+ TCP: config.TCPProbe{
+ QueryResponse: []config.QueryResponse{
{Send: "NICK prober"},
{Send: "USER prober prober prober :prober"},
{Expect: "^:[^ ]+ 001"},
ch <- struct{}{}
}()
registry := prometheus.NewRegistry()
- if !probeTCP(testCTX, ln.Addr().String(), module, registry) {
+ if !ProbeTCP(testCTX, ln.Addr().String(), module, registry) {
t.Fatalf("TCP module failed, expected success.")
}
<-ch
ch <- struct{}{}
}()
registry = prometheus.NewRegistry()
- if probeTCP(testCTX, ln.Addr().String(), module, registry) {
+ if ProbeTCP(testCTX, ln.Addr().String(), module, registry) {
t.Fatalf("TCP module succeeded, expected failure.")
}
mfs, err := registry.Gather()
testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
time.Sleep(time.Millisecond * 100)
- module := Module{
- TCP: TCPProbe{
- QueryResponse: []QueryResponse{
+ module := config.Module{
+ TCP: config.TCPProbe{
+ QueryResponse: []config.QueryResponse{
{
Expect: "SSH-2.0-(OpenSSH_6.9p1) Debian-2",
Send: "CONFIRM ${1}",
ch <- version
}()
registry := prometheus.NewRegistry()
- if !probeTCP(testCTX, ln.Addr().String(), module, registry) {
+ if !ProbeTCP(testCTX, ln.Addr().String(), module, registry) {
t.Fatalf("TCP module failed, expected success.")
}
if got, want := <-ch, "OpenSSH_6.9p1"; got != want {
_, port, _ := net.SplitHostPort(ln.Addr().String())
// Force IPv4
- module := Module{
- TCP: TCPProbe{
+ module := config.Module{
+ TCP: config.TCPProbe{
PreferredIPProtocol: "ip4",
},
}
registry := prometheus.NewRegistry()
- result := probeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result := ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("TCP protocol: \"tcp4\" connection test failed, expected success.")
}
checkRegistryResults(expectedResults, mfs, t)
// Force IPv6
- module = Module{
- TCP: TCPProbe{},
+ module = config.Module{
+ TCP: config.TCPProbe{},
}
registry = prometheus.NewRegistry()
- result = probeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("TCP protocol: \"tcp6\" connection test failed, expected success.")
}
checkRegistryResults(expectedResults, mfs, t)
// Prefer IPv4
- module = Module{
- TCP: TCPProbe{
+ module = config.Module{
+ TCP: config.TCPProbe{
PreferredIPProtocol: "ip4",
},
}
registry = prometheus.NewRegistry()
- result = probeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("TCP protocol: \"tcp\", prefer: \"ip4\" connection test failed, expected success.")
}
checkRegistryResults(expectedResults, mfs, t)
// Prefer IPv6
- module = Module{
- TCP: TCPProbe{
+ module = config.Module{
+ TCP: config.TCPProbe{
PreferredIPProtocol: "ip6",
},
}
registry = prometheus.NewRegistry()
- result = probeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("TCP protocol: \"tcp\", prefer: \"ip6\" connection test failed, expected success.")
}
checkRegistryResults(expectedResults, mfs, t)
// Prefer nothing
- module = Module{
- TCP: TCPProbe{},
+ module = config.Module{
+ TCP: config.TCPProbe{},
}
registry = prometheus.NewRegistry()
- result = probeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("TCP protocol: \"tcp\" connection test failed, expected success.")
}
checkRegistryResults(expectedResults, mfs, t)
// No protocol
- module = Module{
- TCP: TCPProbe{},
+ module = config.Module{
+ TCP: config.TCPProbe{},
}
registry = prometheus.NewRegistry()
- result = probeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
+ result = ProbeTCP(testCTX, net.JoinHostPort("localhost", port), module, registry)
if !result {
t.Fatalf("TCP connection test with protocol unspecified failed, expected success.")
}
testCTX, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
registry := prometheus.NewRegistry()
- if probeTCP(testCTX, ln.Addr().String(), Module{TCP: TCPProbe{
- QueryResponse: []QueryResponse{
+ if ProbeTCP(testCTX, ln.Addr().String(), config.Module{TCP: config.TCPProbe{
+ QueryResponse: []config.QueryResponse{
{
Expect: "SSH-2.0-(OpenSSH_6.9p1) Debian-2",
},
// See the License for the specific language governing permissions and
// limitations under the License.
-package main
+package prober
import (
"crypto/tls"
-package main
+package prober
import (
"net"
-package main
+package prober
import (
"testing"