diff --git a/pkg/api/types.go b/pkg/api/types.go index 9bac8e1cfb1..7eb90d1784d 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -116,11 +116,10 @@ type HTTPGetProbe struct { // LivenessProbe describes a liveness probe to be examined to the container. type LivenessProbe struct { - Enabled bool `yaml:"enabled,omitempty" json:"enabled,omitempty"` // Type of liveness probe. Current legal values "http" Type string `yaml:"type,omitempty" json:"type,omitempty"` // HTTPGetProbe parameters, required if Type == 'http' - HTTPGet HTTPGetProbe `yaml:"httpGet,omitempty" json:"httpGet,omitempty"` + HTTPGet *HTTPGetProbe `yaml:"httpGet,omitempty" json:"httpGet,omitempty"` // Length of time before health checking is activated. In seconds. InitialDelaySeconds int64 `yaml:"initialDelaySeconds,omitempty" json:"initialDelaySeconds,omitempty"` } @@ -141,9 +140,9 @@ type Container struct { // Optional: Defaults to unlimited. Memory int `yaml:"memory,omitempty" json:"memory,omitempty"` // Optional: Defaults to unlimited. - CPU int `yaml:"cpu,omitempty" json:"cpu,omitempty"` - VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty"` - LivenessProbe LivenessProbe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty"` + CPU int `yaml:"cpu,omitempty" json:"cpu,omitempty"` + VolumeMounts []VolumeMount `yaml:"volumeMounts,omitempty" json:"volumeMounts,omitempty"` + LivenessProbe *LivenessProbe `yaml:"livenessProbe,omitempty" json:"livenessProbe,omitempty"` } // Percentile represents a pair which contains a percentage from 0 to 100 and diff --git a/pkg/kubelet/health_check.go b/pkg/kubelet/health_check.go index 7bf9933edf0..62a015df08d 100644 --- a/pkg/kubelet/health_check.go +++ b/pkg/kubelet/health_check.go @@ -25,10 +25,16 @@ import ( "github.com/golang/glog" ) -// HealthChecker is an abstract interface for container health checker. +type HealthCheckStatus int + +const ( + CheckHealthy HealthCheckStatus = 0 + CheckUnhealthy HealthCheckStatus = 1 + CheckUnknown HealthCheckStatus = 2 +) + type HealthChecker interface { - // IsHealthy checks if the container is healthy. - IsHealthy(container api.Container) (bool, error) + HealthCheck(container api.Container) (HealthCheckStatus, error) } type httpDoInterface interface { @@ -51,14 +57,13 @@ type MuxHealthChecker struct { checkers map[string]HealthChecker } -// IsHealthy checks the health of the container by delegating to an appropriate HealthChecker according to container.LivenessProbe.Type. -func (m *MuxHealthChecker) IsHealthy(container api.Container) (bool, error) { +func (m *MuxHealthChecker) HealthCheck(container api.Container) (HealthCheckStatus, error) { checker, ok := m.checkers[container.LivenessProbe.Type] if !ok || checker == nil { glog.Warningf("Failed to find health checker for %s %s", container.Name, container.LivenessProbe.Type) - return true, nil + return CheckUnknown, nil } - return checker.IsHealthy(container) + return checker.HealthCheck(container) } // HTTPHealthChecker is an implementation of HealthChecker which checks container health by sending HTTP Get requests. @@ -76,15 +81,17 @@ func (h *HTTPHealthChecker) findPort(container api.Container, portName string) i return -1 } -// IsHealthy checks if the container is healthy by trying sending HTTP Get requests to the container. -func (h *HTTPHealthChecker) IsHealthy(container api.Container) (bool, error) { +func (h *HTTPHealthChecker) HealthCheck(container api.Container) (HealthCheckStatus, error) { params := container.LivenessProbe.HTTPGet + if params == nil { + return CheckUnknown, fmt.Errorf("Error, no HTTP parameters specified: %v", container) + } port := h.findPort(container, params.Port) if port == -1 { var err error port, err = strconv.ParseInt(params.Port, 10, 0) if err != nil { - return true, err + return CheckUnknown, err } } var host string @@ -100,7 +107,11 @@ func (h *HTTPHealthChecker) IsHealthy(container api.Container) (bool, error) { } if err != nil { // At this point, if it fails, its either a policy (unlikely) or HTTP protocol (likely) error. - return false, nil + return CheckUnhealthy, nil } - return res.StatusCode == http.StatusOK, nil + if res.StatusCode == http.StatusOK { + return CheckHealthy, nil + } + glog.V(1).Infof("Health check failed for %v, Response: %v", container, *res) + return CheckUnhealthy, nil } diff --git a/pkg/kubelet/health_check_test.go b/pkg/kubelet/health_check_test.go index 6aa18dc0425..557f34702b8 100644 --- a/pkg/kubelet/health_check_test.go +++ b/pkg/kubelet/health_check_test.go @@ -46,8 +46,8 @@ func TestHttpHealth(t *testing.T) { } container := api.Container{ - LivenessProbe: api.LivenessProbe{ - HTTPGet: api.HTTPGetProbe{ + LivenessProbe: &api.LivenessProbe{ + HTTPGet: &api.HTTPGetProbe{ Port: "8080", Path: "/foo/bar", }, @@ -55,8 +55,8 @@ func TestHttpHealth(t *testing.T) { }, } - ok, err := check.IsHealthy(container) - if !ok { + ok, err := check.HealthCheck(container) + if ok != CheckHealthy { t.Error("Unexpected unhealthy") } if err != nil { diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 7167de30d50..39ad4b1dd8f 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -732,7 +732,7 @@ func (kl *Kubelet) syncManifest(manifest *api.ContainerManifest, keepChannel cha glog.V(1).Infof("health check errored: %v", err) continue } - if !healthy { + if healthy != CheckHealthy { glog.V(1).Infof("manifest %s container %s is unhealthy.", manifest.ID, container.Name) if err != nil { glog.V(1).Infof("Failed to get container info %v, for %s", err, containerID) @@ -989,16 +989,16 @@ func (kl *Kubelet) GetMachineStats() (*api.ContainerStats, error) { return kl.statsFromContainerPath("/") } -func (kl *Kubelet) healthy(container api.Container, dockerContainer *docker.APIContainers) (bool, error) { +func (kl *Kubelet) healthy(container api.Container, dockerContainer *docker.APIContainers) (HealthCheckStatus, error) { // Give the container 60 seconds to start up. - if !container.LivenessProbe.Enabled { - return true, nil + if container.LivenessProbe == nil { + return CheckHealthy, nil } if time.Now().Unix()-dockerContainer.Created < container.LivenessProbe.InitialDelaySeconds { - return true, nil + return CheckHealthy, nil } if kl.HealthChecker == nil { - return true, nil + return CheckHealthy, nil } - return kl.HealthChecker.IsHealthy(container) + return kl.HealthChecker.HealthCheck(container) } diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index ce071451074..a3a74381e19 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -424,8 +424,8 @@ func TestSyncManifestsDeletes(t *testing.T) { type FalseHealthChecker struct{} -func (f *FalseHealthChecker) IsHealthy(container api.Container) (bool, error) { - return false, nil +func (f *FalseHealthChecker) HealthCheck(container api.Container) (HealthCheckStatus, error) { + return CheckUnhealthy, nil } func TestSyncManifestsUnhealthy(t *testing.T) { @@ -448,8 +448,7 @@ func TestSyncManifestsUnhealthy(t *testing.T) { ID: "foo", Containers: []api.Container{ {Name: "bar", - LivenessProbe: api.LivenessProbe{ - Enabled: true, + LivenessProbe: &api.LivenessProbe{ // Always returns healthy == false Type: "false", },