Skip to content

Commit

Permalink
HTTP: Add Skip Resolve Phase With Proxy option
Browse files Browse the repository at this point in the history
Signed-off-by: Julien Pivotto <roidelapluie@o11y.eu>
  • Loading branch information
roidelapluie committed Jul 11, 2022
1 parent d26fcc6 commit 5406f5c
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 13 deletions.
4 changes: 3 additions & 1 deletion CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ The other placeholders are specified separately.
# HTTP proxy server to use to connect to the targets.
[ proxy_url: <string> ]

# Skip DNS resolution and URL change when an HTTP proxy is set.
[ skip_resolve_phase_with_proxy: <boolean> | default = false ]

# OAuth 2.0 configuration to use to connect to the targets.
oauth2:
[ <oauth2> ]
Expand All @@ -128,7 +131,6 @@ The other placeholders are specified separately.
# The body of the HTTP request used in probe.
body: [ <string> ]


```

#### <http_header_match_spec>
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
30 changes: 18 additions & 12 deletions prober/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
70 changes: 70 additions & 0 deletions prober/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strconv"
"strings"
Expand Down Expand Up @@ -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)
})
}

0 comments on commit 5406f5c

Please sign in to comment.