From: Pascal Gauthier Date: Fri, 7 Dec 2018 15:20:36 +0000 (-0500) Subject: Add force preferred ip protocol (#382) X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=a75399e59a83433800ba896c2b4dd0327c2a3dd6;p=blackbox_exporter.git Add force preferred ip protocol (#382) Signed-off-by: Pascal Gauthier --- diff --git a/CONFIGURATION.md b/CONFIGURATION.md index ed16383..c261c75 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -84,8 +84,9 @@ The other placeholders are specified separately. # HTTP proxy server to use to connect to the targets. [ proxy_url: ] - # The preferred IP protocol of the HTTP probe (ip4, ip6). + # The IP protocol of the HTTP probe (ip4, ip6). [ preferred_ip_protocol: | default = "ip6" ] + [ ip_protocol_fallback: ] # The body of the HTTP request used in probe. body: [ ] @@ -97,8 +98,9 @@ The other placeholders are specified separately. ```yml -# The preferred IP protocol of the TCP probe (ip4, ip6). +# The IP protocol of the TCP probe (ip4, ip6). [ preferred_ip_protocol: | default = "ip6" ] +[ ip_protocol_fallback: ] # The source IP address. [ source_ip_address: ] @@ -125,8 +127,9 @@ tls_config: ```yml -# The preferred IP protocol of the DNS probe (ip4, ip6). +# The IP protocol of the DNS probe (ip4, ip6). [ preferred_ip_protocol: | default = "ip6" ] +[ ip_protocol_fallback: ] # The source IP address. [ source_ip_address: ] @@ -171,8 +174,9 @@ validate_additional_rrs: ```yml -# The preferred IP protocol of the ICMP probe (ip4, ip6). +# The IP protocol of the ICMP probe (ip4, ip6). [ preferred_ip_protocol: | default = "ip6" ] +[ ip_protocol_fallback: ] # The source IP address. [ source_ip_address: ] diff --git a/config/config.go b/config/config.go index 1961b53..2bd5d94 100644 --- a/config/config.go +++ b/config/config.go @@ -54,7 +54,8 @@ type HTTPProbe struct { // Defaults to 2xx. ValidStatusCodes []int `yaml:"valid_status_codes,omitempty"` ValidHTTPVersions []string `yaml:"valid_http_versions,omitempty"` - PreferredIPProtocol string `yaml:"preferred_ip_protocol,omitempty"` + IPProtocol string `yaml:"preferred_ip_protocol,omitempty"` + IPProtocolFallback bool `yaml:"ip_protocol_fallback,omitempty"` NoFollowRedirects bool `yaml:"no_follow_redirects,omitempty"` FailIfSSL bool `yaml:"fail_if_ssl,omitempty"` FailIfNotSSL bool `yaml:"fail_if_not_ssl,omitempty"` @@ -73,30 +74,33 @@ type QueryResponse struct { } type TCPProbe struct { - PreferredIPProtocol string `yaml:"preferred_ip_protocol,omitempty"` - SourceIPAddress string `yaml:"source_ip_address,omitempty"` - QueryResponse []QueryResponse `yaml:"query_response,omitempty"` - TLS bool `yaml:"tls,omitempty"` - TLSConfig config.TLSConfig `yaml:"tls_config,omitempty"` + IPProtocol string `yaml:"preferred_ip_protocol,omitempty"` + IPProtocolFallback bool `yaml:"ip_protocol_fallback,omitempty"` + SourceIPAddress string `yaml:"source_ip_address,omitempty"` + QueryResponse []QueryResponse `yaml:"query_response,omitempty"` + TLS bool `yaml:"tls,omitempty"` + TLSConfig config.TLSConfig `yaml:"tls_config,omitempty"` } type ICMPProbe struct { - PreferredIPProtocol string `yaml:"preferred_ip_protocol,omitempty"` // Defaults to "ip6". - SourceIPAddress string `yaml:"source_ip_address,omitempty"` - PayloadSize int `yaml:"payload_size,omitempty"` - DontFragment bool `yaml:"dont_fragment,omitempty"` + IPProtocol string `yaml:"preferred_ip_protocol,omitempty"` // Defaults to "ip6". + IPProtocolFallback bool `yaml:"ip_protocol_fallback,omitempty"` + SourceIPAddress string `yaml:"source_ip_address,omitempty"` + PayloadSize int `yaml:"payload_size,omitempty"` + DontFragment bool `yaml:"dont_fragment,omitempty"` } type DNSProbe struct { - PreferredIPProtocol string `yaml:"preferred_ip_protocol,omitempty"` - SourceIPAddress string `yaml:"source_ip_address,omitempty"` - TransportProtocol string `yaml:"transport_protocol,omitempty"` - QueryName string `yaml:"query_name,omitempty"` - QueryType string `yaml:"query_type,omitempty"` // Defaults to ANY. - ValidRcodes []string `yaml:"valid_rcodes,omitempty"` // Defaults to NOERROR. - ValidateAnswer DNSRRValidator `yaml:"validate_answer_rrs,omitempty"` - ValidateAuthority DNSRRValidator `yaml:"validate_authority_rrs,omitempty"` - ValidateAdditional DNSRRValidator `yaml:"validate_additional_rrs,omitempty"` + IPProtocol string `yaml:"preferred_ip_protocol,omitempty"` + IPProtocolFallback bool `yaml:"ip_protocol_fallback,omitempty"` + SourceIPAddress string `yaml:"source_ip_address,omitempty"` + TransportProtocol string `yaml:"transport_protocol,omitempty"` + QueryName string `yaml:"query_name,omitempty"` + QueryType string `yaml:"query_type,omitempty"` // Defaults to ANY. + ValidRcodes []string `yaml:"valid_rcodes,omitempty"` // Defaults to NOERROR. + ValidateAnswer DNSRRValidator `yaml:"validate_answer_rrs,omitempty"` + ValidateAuthority DNSRRValidator `yaml:"validate_authority_rrs,omitempty"` + ValidateAdditional DNSRRValidator `yaml:"validate_additional_rrs,omitempty"` } type DNSRRValidator struct { diff --git a/config/testdata/blackbox-good.yml b/config/testdata/blackbox-good.yml index af15e67..d0a1f0c 100644 --- a/config/testdata/blackbox-good.yml +++ b/config/testdata/blackbox-good.yml @@ -63,5 +63,6 @@ modules: dns: query_name: example.com preferred_ip_protocol: ip4 + ip_protocol_fallback: false validate_answer_rrs: fail_if_matches_regexp: [test] diff --git a/example.yml b/example.yml index 17beee0..39786fb 100644 --- a/example.yml +++ b/example.yml @@ -19,6 +19,7 @@ modules: tls_config: insecure_skip_verify: false preferred_ip_protocol: "ip4" # defaults to "ip6" + ip_protocol_fallback: false # no fallback to "ip6" http_post_2xx: prober: http timeout: 5s @@ -120,5 +121,5 @@ modules: prober: dns dns: transport_protocol: "tcp" # defaults to "udp" - preferred_ip_protocol: "ip4" # defaults to "ip6" + preferred_ip_protocol: "ip4" # defaults to "ip6" query_name: "www.prometheus.io" diff --git a/prober/dns.go b/prober/dns.go index d11aa64..c5078f6 100644 --- a/prober/dns.go +++ b/prober/dns.go @@ -129,7 +129,7 @@ func ProbeDNS(ctx context.Context, target string, module config.Module, registry port = "53" targetAddr = target } - ip, _, err = chooseProtocol(module.DNS.PreferredIPProtocol, targetAddr, registry, logger) + ip, _, err = chooseProtocol(module.DNS.IPProtocol, module.DNS.IPProtocolFallback, targetAddr, registry, logger) if err != nil { level.Error(logger).Log("msg", "Error resolving address", "err", err) return false diff --git a/prober/dns_test.go b/prober/dns_test.go index f0b6f40..525d44e 100644 --- a/prober/dns_test.go +++ b/prober/dns_test.go @@ -91,21 +91,21 @@ func TestRecursiveDNSResponse(t *testing.T) { }{ { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", }, true, }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", - ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"}, + IPProtocol: "ipv4", + QueryName: "example.com", + ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"}, }, false, }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", ValidateAnswer: config.DNSRRValidator{ FailIfMatchesRegexp: []string{".*7200.*"}, FailIfNotMatchesRegexp: []string{".*3600.*"}, @@ -114,8 +114,8 @@ func TestRecursiveDNSResponse(t *testing.T) { }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", ValidateAuthority: config.DNSRRValidator{ FailIfMatchesRegexp: []string{".*7200.*"}, }, @@ -123,8 +123,8 @@ func TestRecursiveDNSResponse(t *testing.T) { }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", ValidateAdditional: config.DNSRRValidator{ FailIfNotMatchesRegexp: []string{".*3600.*"}, }, @@ -217,27 +217,27 @@ func TestAuthoritativeDNSResponse(t *testing.T) { }{ { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", }, true, }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", - QueryType: "SOA", + IPProtocol: "ipv4", + QueryName: "example.com", + QueryType: "SOA", }, true, }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", - ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"}, + IPProtocol: "ipv4", + QueryName: "example.com", + ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"}, }, false, }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", ValidateAnswer: config.DNSRRValidator{ FailIfMatchesRegexp: []string{".*3600.*"}, FailIfNotMatchesRegexp: []string{".*3600.*"}, @@ -246,8 +246,8 @@ func TestAuthoritativeDNSResponse(t *testing.T) { }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", ValidateAnswer: config.DNSRRValidator{ FailIfMatchesRegexp: []string{".*7200.*"}, FailIfNotMatchesRegexp: []string{".*7200.*"}, @@ -256,8 +256,8 @@ func TestAuthoritativeDNSResponse(t *testing.T) { }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", ValidateAuthority: config.DNSRRValidator{ FailIfNotMatchesRegexp: []string{"ns.*.isp.net"}, }, @@ -265,8 +265,8 @@ func TestAuthoritativeDNSResponse(t *testing.T) { }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", ValidateAdditional: config.DNSRRValidator{ FailIfNotMatchesRegexp: []string{"^ns.*.isp"}, }, @@ -274,8 +274,8 @@ func TestAuthoritativeDNSResponse(t *testing.T) { }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", ValidateAdditional: config.DNSRRValidator{ FailIfMatchesRegexp: []string{"^ns.*.isp"}, }, @@ -321,29 +321,29 @@ func TestServfailDNSResponse(t *testing.T) { }{ { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", + IPProtocol: "ipv4", + QueryName: "example.com", }, false, }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", - ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"}, + IPProtocol: "ipv4", + QueryName: "example.com", + ValidRcodes: []string{"SERVFAIL", "NXDOMAIN"}, }, true, }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", - QueryType: "NOT_A_VALID_QUERY_TYPE", + IPProtocol: "ipv4", + QueryName: "example.com", + QueryType: "NOT_A_VALID_QUERY_TYPE", }, false, }, { config.DNSProbe{ - PreferredIPProtocol: "ipv4", - QueryName: "example.com", - ValidRcodes: []string{"NOT_A_VALID_RCODE"}, + IPProtocol: "ipv4", + QueryName: "example.com", + ValidRcodes: []string{"NOT_A_VALID_RCODE"}, }, false, }, } @@ -398,9 +398,9 @@ func TestDNSProtocol(t *testing.T) { module := config.Module{ Timeout: time.Second, DNS: config.DNSProbe{ - QueryName: "example.com", - TransportProtocol: protocol, - PreferredIPProtocol: "ip4", + QueryName: "example.com", + TransportProtocol: protocol, + IPProtocol: "ip4", }, } registry := prometheus.NewRegistry() @@ -424,9 +424,9 @@ func TestDNSProtocol(t *testing.T) { module = config.Module{ Timeout: time.Second, DNS: config.DNSProbe{ - QueryName: "example.com", - TransportProtocol: protocol, - PreferredIPProtocol: "ip6", + QueryName: "example.com", + TransportProtocol: protocol, + IPProtocol: "ip6", }, } registry = prometheus.NewRegistry() @@ -449,9 +449,9 @@ func TestDNSProtocol(t *testing.T) { module = config.Module{ Timeout: time.Second, DNS: config.DNSProbe{ - QueryName: "example.com", - TransportProtocol: protocol, - PreferredIPProtocol: "ip6", + QueryName: "example.com", + TransportProtocol: protocol, + IPProtocol: "ip6", }, } registry = prometheus.NewRegistry() @@ -474,9 +474,9 @@ func TestDNSProtocol(t *testing.T) { module = config.Module{ Timeout: time.Second, DNS: config.DNSProbe{ - QueryName: "example.com", - TransportProtocol: protocol, - PreferredIPProtocol: "ip4", + QueryName: "example.com", + TransportProtocol: protocol, + IPProtocol: "ip4", }, } registry = prometheus.NewRegistry() diff --git a/prober/http.go b/prober/http.go index 71d1dec..542f312 100644 --- a/prober/http.go +++ b/prober/http.go @@ -203,7 +203,7 @@ func ProbeHTTP(ctx context.Context, target string, module config.Module, registr targetHost = targetURL.Host } - ip, lookupTime, err := chooseProtocol(module.HTTP.PreferredIPProtocol, targetHost, registry, logger) + ip, lookupTime, err := chooseProtocol(module.HTTP.IPProtocol, module.HTTP.IPProtocolFallback, targetHost, registry, logger) if err != nil { level.Error(logger).Log("msg", "Error resolving address", "err", err) return false diff --git a/prober/http_test.go b/prober/http_test.go index 60b4271..a7deaa8 100644 --- a/prober/http_test.go +++ b/prober/http_test.go @@ -59,7 +59,7 @@ func TestHTTPStatusCodes(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ValidStatusCodes: test.ValidStatusCodes}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, ValidStatusCodes: test.ValidStatusCodes}}, registry, log.NewNopLogger()) body := recorder.Body.String() if result != test.ShouldSucceed { t.Fatalf("Test %d had unexpected result: %s", i, body) @@ -85,7 +85,8 @@ func TestValidHTTPVersion(t *testing.T) { registry := prometheus.NewRegistry() result := ProbeHTTP(context.Background(), ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ - ValidHTTPVersions: test.ValidHTTPVersions, + IPProtocolFallback: true, + ValidHTTPVersions: test.ValidHTTPVersions, }}, registry, log.NewNopLogger()) body := recorder.Body.String() if result != test.ShouldSucceed { @@ -107,7 +108,7 @@ func TestRedirectFollowed(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{}}, registry, log.NewNopLogger()) + result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true}}, registry, log.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Redirect test failed unexpectedly, got %s", body) @@ -135,7 +136,7 @@ func TestRedirectNotFollowed(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{NoFollowRedirects: true, ValidStatusCodes: []int{302}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, NoFollowRedirects: true, ValidStatusCodes: []int{302}}}, registry, log.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Redirect test failed unexpectedly, got %s", body) @@ -156,7 +157,7 @@ func TestPost(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{Method: "POST"}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, Method: "POST"}}, registry, log.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Post test failed unexpectedly, got %s", body) @@ -174,6 +175,7 @@ func TestBasicAuth(t *testing.T) { defer cancel() result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ + IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false}, BasicAuth: &pconfig.BasicAuth{Username: "username", Password: "password"}, @@ -196,6 +198,7 @@ func TestBearerToken(t *testing.T) { defer cancel() result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ + IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{ BearerToken: pconfig.Secret("mysecret"), }, @@ -216,7 +219,7 @@ func TestFailIfNotSSL(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotSSL: true}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfNotSSL: true}}, registry, log.NewNopLogger()) body := recorder.Body.String() if result { t.Fatalf("Fail if not SSL test suceeded unexpectedly, got %s", body) @@ -242,7 +245,7 @@ func TestFailIfMatchesRegexp(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database"}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfMatchesRegexp: []string{"could not connect to database"}}}, registry, log.NewNopLogger()) body := recorder.Body.String() if result { t.Fatalf("Regexp test succeeded unexpectedly, got %s", body) @@ -264,7 +267,7 @@ func TestFailIfMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database"}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfMatchesRegexp: []string{"could not connect to database"}}}, registry, log.NewNopLogger()) body = recorder.Body.String() if !result { t.Fatalf("Regexp test failed unexpectedly, got %s", body) @@ -288,7 +291,7 @@ func TestFailIfMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}}, registry, log.NewNopLogger()) body = recorder.Body.String() if result { t.Fatalf("Regexp test succeeded unexpectedly, got %s", body) @@ -302,7 +305,7 @@ func TestFailIfMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfMatchesRegexp: []string{"could not connect to database", "internal error"}}}, registry, log.NewNopLogger()) body = recorder.Body.String() if !result { t.Fatalf("Regexp test failed unexpectedly, got %s", body) @@ -320,7 +323,7 @@ func TestFailIfNotMatchesRegexp(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here"}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfNotMatchesRegexp: []string{"Download the latest version here"}}}, registry, log.NewNopLogger()) body := recorder.Body.String() if result { t.Fatalf("Regexp test succeeded unexpectedly, got %s", body) @@ -334,7 +337,7 @@ func TestFailIfNotMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here"}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfNotMatchesRegexp: []string{"Download the latest version here"}}}, registry, log.NewNopLogger()) body = recorder.Body.String() if !result { t.Fatalf("Regexp test failed unexpectedly, got %s", body) @@ -350,7 +353,7 @@ func TestFailIfNotMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}}, registry, log.NewNopLogger()) body = recorder.Body.String() if result { t.Fatalf("Regexp test succeeded unexpectedly, got %s", body) @@ -364,7 +367,7 @@ func TestFailIfNotMatchesRegexp(t *testing.T) { recorder = httptest.NewRecorder() registry = prometheus.NewRegistry() result = ProbeHTTP(testCTX, ts.URL, - config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}}, registry, log.NewNopLogger()) + config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true, FailIfNotMatchesRegexp: []string{"Download the latest version here", "Copyright 2015"}}}, registry, log.NewNopLogger()) body = recorder.Body.String() if !result { t.Fatalf("Regexp test failed unexpectedly, got %s", body) @@ -396,7 +399,7 @@ func TestHTTPHeaders(t *testing.T) { testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ - Headers: headers, + Headers: headers, IPProtocolFallback: true, }}, registry, log.NewNopLogger()) if !result { t.Fatalf("Probe failed unexpectedly.") @@ -414,6 +417,7 @@ func TestFailIfSelfSignedCA(t *testing.T) { defer cancel() result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ + IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false}, }, @@ -443,6 +447,7 @@ func TestSucceedIfSelfSignedCA(t *testing.T) { defer cancel() result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ + IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, }, @@ -472,6 +477,7 @@ func TestTLSConfigIsIgnoredForPlainHTTP(t *testing.T) { defer cancel() result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ + IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: false}, }, @@ -525,7 +531,8 @@ func TestHTTPUsesTargetAsTLSServerName(t *testing.T) { module := config.Module{ Timeout: time.Second, HTTP: config.HTTPProbe{ - PreferredIPProtocol: "ip4", + IPProtocol: "ip4", + IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{ CAFile: tmpCaFile.Name(), @@ -556,6 +563,7 @@ func TestHTTPPhases(t *testing.T) { defer cancel() result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{ + IPProtocolFallback: true, HTTPClientConfig: pconfig.HTTPClientConfig{ TLSConfig: pconfig.TLSConfig{InsecureSkipVerify: true}, }, @@ -632,7 +640,7 @@ func TestCookieJar(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{}}, registry, log.NewNopLogger()) + result := ProbeHTTP(testCTX, ts.URL, config.Module{Timeout: time.Second, HTTP: config.HTTPProbe{IPProtocolFallback: true}}, registry, log.NewNopLogger()) body := recorder.Body.String() if !result { t.Fatalf("Redirect test failed unexpectedly, got %s", body) diff --git a/prober/icmp.go b/prober/icmp.go index 78bf6c2..2e01265 100644 --- a/prober/icmp.go +++ b/prober/icmp.go @@ -64,7 +64,7 @@ func ProbeICMP(ctx context.Context, target string, module config.Module, registr timeoutDeadline, _ := ctx.Deadline() deadline := time.Now().Add(timeoutDeadline.Sub(time.Now())) - ip, lookupTime, err := chooseProtocol(module.ICMP.PreferredIPProtocol, target, registry, logger) + ip, lookupTime, err := chooseProtocol(module.ICMP.IPProtocol, module.ICMP.IPProtocolFallback, target, registry, logger) if err != nil { level.Warn(logger).Log("msg", "Error resolving address", "err", err) return false diff --git a/prober/tcp.go b/prober/tcp.go index 48b5cb0..5bc13db 100644 --- a/prober/tcp.go +++ b/prober/tcp.go @@ -38,7 +38,7 @@ func dialTCP(ctx context.Context, target string, module config.Module, registry return nil, err } - ip, _, err := chooseProtocol(module.TCP.PreferredIPProtocol, targetAddress, registry, logger) + ip, _, err := chooseProtocol(module.TCP.IPProtocol, module.TCP.IPProtocolFallback, targetAddress, registry, logger) if err != nil { level.Error(logger).Log("msg", "Error resolving address", "err", err) return nil, err diff --git a/prober/tcp_test.go b/prober/tcp_test.go index d1afe06..0e3709c 100644 --- a/prober/tcp_test.go +++ b/prober/tcp_test.go @@ -51,7 +51,7 @@ 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(), config.Module{}, registry, log.NewNopLogger()) { + if !ProbeTCP(testCTX, ln.Addr().String(), config.Module{TCP: config.TCPProbe{IPProtocolFallback: true}}, registry, log.NewNopLogger()) { t.Fatalf("TCP module failed, expected success.") } <-ch @@ -62,7 +62,7 @@ func TestTCPConnectionFails(t *testing.T) { registry := prometheus.NewRegistry() testCTX, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - if ProbeTCP(testCTX, ":0", config.Module{}, registry, log.NewNopLogger()) { + if ProbeTCP(testCTX, ":0", config.Module{TCP: config.TCPProbe{IPProtocolFallback: true}}, registry, log.NewNopLogger()) { t.Fatalf("TCP module suceeded, expected failure.") } } @@ -129,8 +129,9 @@ func TestTCPConnectionWithTLS(t *testing.T) { // Expect name-verified TLS connection. module := config.Module{ TCP: config.TCPProbe{ - PreferredIPProtocol: "ipv4", - TLS: true, + IPProtocol: "ipv4", + IPProtocolFallback: true, + TLS: true, TLSConfig: pconfig.TLSConfig{ CAFile: tmpCaFile.Name(), InsecureSkipVerify: false, @@ -205,6 +206,7 @@ func TestTCPConnectionQueryResponseStartTLS(t *testing.T) { // Define some (bogus) example SMTP dialog with STARTTLS. module := config.Module{ TCP: config.TCPProbe{ + IPProtocolFallback: true, QueryResponse: []config.QueryResponse{ {Expect: "^220.*ESMTP.*$"}, {Send: "EHLO tls.prober"}, @@ -299,6 +301,7 @@ func TestTCPConnectionQueryResponseIRC(t *testing.T) { module := config.Module{ TCP: config.TCPProbe{ + IPProtocolFallback: true, QueryResponse: []config.QueryResponse{ {Send: "NICK prober"}, {Send: "USER prober prober prober :prober"}, @@ -367,6 +370,7 @@ func TestTCPConnectionQueryResponseMatching(t *testing.T) { time.Sleep(time.Millisecond * 100) module := config.Module{ TCP: config.TCPProbe{ + IPProtocolFallback: true, QueryResponse: []config.QueryResponse{ { Expect: "SSH-2.0-(OpenSSH_6.9p1) Debian-2", @@ -433,7 +437,8 @@ func TestTCPConnectionProtocol(t *testing.T) { // Force IPv4 module := config.Module{ TCP: config.TCPProbe{ - PreferredIPProtocol: "ip4", + IPProtocol: "ip4", + IPProtocolFallback: true, }, } @@ -473,7 +478,7 @@ func TestTCPConnectionProtocol(t *testing.T) { // Prefer IPv4 module = config.Module{ TCP: config.TCPProbe{ - PreferredIPProtocol: "ip4", + IPProtocol: "ip4", }, } @@ -494,7 +499,8 @@ func TestTCPConnectionProtocol(t *testing.T) { // Prefer IPv6 module = config.Module{ TCP: config.TCPProbe{ - PreferredIPProtocol: "ip6", + IPProtocol: "ip6", + IPProtocolFallback: true, }, } @@ -571,6 +577,7 @@ func TestPrometheusTimeoutTCP(t *testing.T) { defer cancel() registry := prometheus.NewRegistry() if ProbeTCP(testCTX, ln.Addr().String(), config.Module{TCP: config.TCPProbe{ + IPProtocolFallback: true, QueryResponse: []config.QueryResponse{ { Expect: "SSH-2.0-(OpenSSH_6.9p1) Debian-2", diff --git a/prober/utils.go b/prober/utils.go index a2228a9..323868b 100644 --- a/prober/utils.go +++ b/prober/utils.go @@ -10,8 +10,8 @@ import ( "github.com/prometheus/client_golang/prometheus" ) -// Returns the IP for the preferedIPProtocol and lookup time. -func chooseProtocol(preferredIPProtocol string, target string, registry *prometheus.Registry, logger log.Logger) (ip *net.IPAddr, lookupTime float64, err error) { +// Returns the IP for the IPProtocol and lookup time. +func chooseProtocol(IPProtocol string, fallbackIPProtocol bool, target string, registry *prometheus.Registry, logger log.Logger) (ip *net.IPAddr, lookupTime float64, err error) { var fallbackProtocol string probeDNSLookupTimeSeconds := prometheus.NewGauge(prometheus.GaugeOpts{ Name: "probe_dns_lookup_time_seconds", @@ -25,21 +25,21 @@ func chooseProtocol(preferredIPProtocol string, target string, registry *prometh registry.MustRegister(probeIPProtocolGauge) registry.MustRegister(probeDNSLookupTimeSeconds) - if preferredIPProtocol == "ip6" || preferredIPProtocol == "" { - preferredIPProtocol = "ip6" + if IPProtocol == "ip6" || IPProtocol == "" { + IPProtocol = "ip6" fallbackProtocol = "ip4" } else { - preferredIPProtocol = "ip4" + IPProtocol = "ip4" fallbackProtocol = "ip6" } - if preferredIPProtocol == "ip6" { + if IPProtocol == "ip6" { fallbackProtocol = "ip4" } else { fallbackProtocol = "ip6" } - level.Info(logger).Log("msg", "Resolving target address", "preferred_ip_protocol", preferredIPProtocol) + level.Info(logger).Log("msg", "Resolving target address", "ip_protocol", IPProtocol) resolveStart := time.Now() defer func() { @@ -47,10 +47,15 @@ func chooseProtocol(preferredIPProtocol string, target string, registry *prometh probeDNSLookupTimeSeconds.Add(lookupTime) }() - ip, err = net.ResolveIPAddr(preferredIPProtocol, target) + ip, err = net.ResolveIPAddr(IPProtocol, target) if err != nil { - level.Warn(logger).Log("msg", "Resolution with preferred IP protocol failed, attempting fallback protocol", "fallback_protocol", fallbackProtocol, "err", err) - ip, err = net.ResolveIPAddr(fallbackProtocol, target) + if fallbackIPProtocol == false { + level.Error(logger).Log("msg", "Resolution with IP protocol failed (fallback_ip_protocol is false): err", err) + } else { + level.Warn(logger).Log("msg", "Resolution with IP protocol failed, attempting fallback protocol", "fallback_protocol", fallbackProtocol, "err", err) + ip, err = net.ResolveIPAddr(fallbackProtocol, target) + } + if err != nil { return ip, 0.0, err }