From 2c816a41d7a94746722f08affaad4405b38bca24 Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Mon, 11 Jul 2022 17:16:13 +0200 Subject: [PATCH] HTTP: Add Skip Resolve Phase With Proxy option Signed-off-by: Julien Pivotto --- blackbox.yml | 50 ++++---------------------------- config/config.go | 1 + prober/http.go | 30 +++++++++++-------- prober/http_test.go | 70 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 57 deletions(-) diff --git a/blackbox.yml b/blackbox.yml index 62884bcb6..37f28dfaf 100644 --- a/blackbox.yml +++ b/blackbox.yml @@ -1,49 +1,9 @@ modules: http_2xx: prober: http - http_post_2xx: - prober: http http: - method: POST - tcp_connect: - prober: tcp - pop3s_banner: - prober: tcp - tcp: - query_response: - - expect: "^+OK" - tls: true - tls_config: - insecure_skip_verify: false - grpc: - prober: grpc - grpc: - tls: true - preferred_ip_protocol: "ip4" - grpc_plain: - prober: grpc - grpc: - tls: false - service: "service1" - ssh_banner: - prober: tcp - tcp: - query_response: - - expect: "^SSH-2.0-" - - send: "SSH-2.0-blackbox-ssh-check" - irc_banner: - prober: tcp - tcp: - query_response: - - send: "NICK prober" - - send: "USER prober prober prober :prober" - - expect: "PING :([^ ]+)" - send: "PONG ${1}" - - expect: "^:[^ ]+ 001" - icmp: - prober: icmp - icmp_ttl5: - prober: icmp - timeout: 5s - icmp: - ttl: 5 \ No newline at end of file + oauth2: + token_url: http://127.0.0.1:8080/realms/TEST/protocol/openid-connect/token + client_id: testcli + client_secret: 3bffzpkhdAZEZemnuFm6QOxeOncsZM94 + # client_secret_file: secret diff --git a/config/config.go b/config/config.go index 8094b29e1..7a238244a 100644 --- a/config/config.go +++ b/config/config.go @@ -210,6 +210,7 @@ type HTTPProbe struct { ValidHTTPVersions []string `yaml:"valid_http_versions,omitempty"` IPProtocol string `yaml:"preferred_ip_protocol,omitempty"` IPProtocolFallback bool `yaml:"ip_protocol_fallback,omitempty"` + SkipResolvePhaseWithProxy bool `yaml:"skip_resolve_phase_with_proxy,omitempty"` NoFollowRedirects *bool `yaml:"no_follow_redirects,omitempty"` FailIfSSL bool `yaml:"fail_if_ssl,omitempty"` FailIfNotSSL bool `yaml:"fail_if_not_ssl,omitempty"` diff --git a/prober/http.go b/prober/http.go index 99d38a2bf..802bdc931 100644 --- a/prober/http.go +++ b/prober/http.go @@ -333,11 +333,15 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr targetHost := targetURL.Hostname() targetPort := targetURL.Port() - ip, lookupTime, err := chooseProtocol(ctx, module.HTTP.IPProtocol, module.HTTP.IPProtocolFallback, targetHost, registry, logger) - durationGaugeVec.WithLabelValues("resolve").Add(lookupTime) - if err != nil { - level.Error(logger).Log("msg", "Error resolving address", "err", err) - return false + var ip *net.IPAddr + if !module.HTTP.SkipResolvePhaseWithProxy || module.HTTP.HTTPClientConfig.ProxyURL.URL == nil { + var lookupTime float64 + ip, lookupTime, err = chooseProtocol(ctx, module.HTTP.IPProtocol, module.HTTP.IPProtocolFallback, targetHost, registry, logger) + durationGaugeVec.WithLabelValues("resolve").Add(lookupTime) + if err != nil { + level.Error(logger).Log("msg", "Error resolving address", "err", err) + return false + } } // Do not move the following variable to global scope. The cases.Caser returned by @@ -404,16 +408,18 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr httpConfig.Method = "GET" } - // Replace the host field in the URL with the IP we resolved. origHost := targetURL.Host - if targetPort == "" { - if strings.Contains(ip.String(), ":") { - targetURL.Host = "[" + ip.String() + "]" + if ip != nil { + // Replace the host field in the URL with the IP we resolved. + if targetPort == "" { + if strings.Contains(ip.String(), ":") { + targetURL.Host = "[" + ip.String() + "]" + } else { + targetURL.Host = ip.String() + } } else { - targetURL.Host = ip.String() + targetURL.Host = net.JoinHostPort(ip.String(), targetPort) } - } else { - targetURL.Host = net.JoinHostPort(ip.String(), targetPort) } var body io.Reader diff --git a/prober/http_test.go b/prober/http_test.go index cd277618a..078475c14 100644 --- a/prober/http_test.go +++ b/prober/http_test.go @@ -25,6 +25,7 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "net/url" "os" "strconv" "strings" @@ -1338,3 +1339,72 @@ func TestCookieJar(t *testing.T) { t.Fatalf("Redirect test failed unexpectedly, got %s", body) } } + +func TestSkipResolvePhase(t *testing.T) { + if testing.Short() { + t.Skip("skipping network dependent test") + } + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) + })) + defer ts.Close() + + t.Run("Without Proxy", func(t *testing.T) { + registry := prometheus.NewRegistry() + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + result := ProbeHTTP(testCTX, ts.URL, + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: pconfig.DefaultHTTPClientConfig, SkipResolvePhaseWithProxy: true}}, registry, log.NewNopLogger()) + if !result { + t.Fatalf("Probe unsuccessful") + } + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + expectedMetrics := map[string]map[string]map[string]struct{}{ + "probe_http_duration_seconds": { + "phase": { + "connect": {}, + "processing": {}, + "resolve": {}, + "transfer": {}, + "tls": {}, + }, + }, + } + + checkMetrics(expectedMetrics, mfs, t) + }) + t.Run("With Proxy", func(t *testing.T) { + registry := prometheus.NewRegistry() + testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + httpCfg := pconfig.DefaultHTTPClientConfig + u, err := url.Parse("http://127.0.0.1:3128") + if err != nil { + t.Fatalf(err.Error()) + } + httpCfg.ProxyURL = pconfig.URL{ + URL: u, + } + ProbeHTTP(testCTX, ts.URL, + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, HTTPClientConfig: httpCfg, SkipResolvePhaseWithProxy: true}}, registry, log.NewNopLogger()) + mfs, err := registry.Gather() + if err != nil { + t.Fatal(err) + } + expectedMetrics := map[string]map[string]map[string]struct{}{ + "probe_http_duration_seconds": { + "phase": { + "connect": {}, + "processing": {}, + "transfer": {}, + "tls": {}, + }, + }, + } + + checkMetrics(expectedMetrics, mfs, t) + }) +}