Add timeouts to HealthChecks and retry checks

Fixes issue #3532. Added timeouts for HTTP and TCP checks
and enabled kubelet/probe to kubelet#maxRetries times
before declaring Failure.

Added Probe.TimeoutSecs to API

Probe variants now check container.LivenessProbe.TimeoutSeconds
Also added a test for timeouts in http_test.go.
This commit is contained in:
George Kuan
2015-01-28 20:35:49 -08:00
parent e335e2d3e2
commit e8c33b7916
12 changed files with 60 additions and 21 deletions

View File

@@ -21,6 +21,7 @@ import (
"net/http"
"net/url"
"strconv"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
@@ -28,16 +29,17 @@ import (
)
func New() HTTPProber {
return HTTPProber{&http.Client{}}
transport := &http.Transport{}
return HTTPProber{transport}
}
type HTTPProber struct {
client HTTPGetInterface
transport *http.Transport
}
// Probe returns a ProbeRunner capable of running an http check.
func (pr *HTTPProber) Probe(host string, port int, path string) (probe.Status, error) {
return DoHTTPProbe(formatURL(host, port, path), pr.client)
func (pr *HTTPProber) Probe(host string, port int, path string, timeout time.Duration) (probe.Status, error) {
return DoHTTPProbe(formatURL(host, port, path), &http.Client{Timeout: timeout, Transport: pr.transport})
}
type HTTPGetInterface interface {

View File

@@ -23,6 +23,7 @@ import (
"net/url"
"strconv"
"testing"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
)
@@ -46,20 +47,25 @@ func TestFormatURL(t *testing.T) {
}
func TestHTTPProbeChecker(t *testing.T) {
handleReq := func(s int) func(w http.ResponseWriter) {
return func(w http.ResponseWriter) { w.WriteHeader(s) }
}
prober := New()
testCases := []struct {
status int
health probe.Status
handler func(w http.ResponseWriter)
health probe.Status
}{
// The probe will be filled in below. This is primarily testing that an HTTP GET happens.
{http.StatusOK, probe.Success},
{-1, probe.Failure},
{handleReq(http.StatusOK), probe.Success},
{handleReq(-1), probe.Failure},
{func(w http.ResponseWriter) { time.Sleep(3 * time.Second) }, probe.Failure},
}
for _, test := range testCases {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(test.status)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
test.handler(w)
}))
u, err := url.Parse(ts.URL)
u, err := url.Parse(server.URL)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
@@ -71,7 +77,7 @@ func TestHTTPProbeChecker(t *testing.T) {
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
health, err := prober.Probe(host, p, "")
health, err := prober.Probe(host, p, "", 1*time.Second)
if test.health == probe.Unknown && err == nil {
t.Errorf("Expected error")
}

View File

@@ -19,6 +19,7 @@ package tcp
import (
"net"
"strconv"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
@@ -31,16 +32,16 @@ func New() TCPProber {
type TCPProber struct{}
func (pr TCPProber) Probe(host string, port int) (probe.Status, error) {
return DoTCPProbe(net.JoinHostPort(host, strconv.Itoa(port)))
func (pr TCPProber) Probe(host string, port int, timeout time.Duration) (probe.Status, error) {
return DoTCPProbe(net.JoinHostPort(host, strconv.Itoa(port)), timeout)
}
// DoTCPProbe checks that a TCP socket to the address can be opened.
// If the socket can be opened, it returns Success
// If the socket fails to open, it returns Failure.
// This is exported because some other packages may want to do direct TCP probes.
func DoTCPProbe(addr string) (probe.Status, error) {
conn, err := net.Dial("tcp", addr)
func DoTCPProbe(addr string, timeout time.Duration) (probe.Status, error) {
conn, err := net.DialTimeout("tcp", addr, timeout)
if err != nil {
return probe.Failure, nil
}

View File

@@ -23,6 +23,7 @@ import (
"net/url"
"strconv"
"testing"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
)
@@ -59,7 +60,7 @@ func TestTcpHealthChecker(t *testing.T) {
if !test.usePort {
p = -1
}
status, err := prober.Probe(host, p)
status, err := prober.Probe(host, p, 1*time.Second)
if status != test.expectedStatus {
t.Errorf("expected: %v, got: %v", test.expectedStatus, status)
}