Commit f38c6072 authored by Victor Marmol's avatar Victor Marmol

Move Prober to its own subpackage.

This will allow it to be reused by the runtimes.
parent 33b8f487
......@@ -20,7 +20,6 @@ import (
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
)
// HandlerRunner runs a lifecycle handler for a container.
......@@ -28,11 +27,6 @@ type HandlerRunner interface {
Run(containerID string, pod *api.Pod, container *api.Container, handler *api.Handler) error
}
// Prober checks the healthiness of a container.
type Prober interface {
Probe(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, error)
}
// RunContainerOptionsGenerator generates the options that necessary for
// container runtime to run a container.
// TODO(yifan): Remove netMode, ipcMode.
......
......@@ -43,6 +43,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/envvars"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/metrics"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/prober"
kubeletTypes "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
......@@ -255,7 +256,7 @@ func NewMainKubelet(
klet.containerManager = containerManager
klet.podManager = newBasicPodManager(klet.kubeClient)
klet.prober = newProber(klet.runner, klet.readinessManager, klet.containerRefManager, klet.recorder)
klet.prober = prober.New(klet.runner, klet.readinessManager, klet.containerRefManager, klet.recorder)
klet.handlerRunner = newHandlerRunner(klet.httpClient, klet.runner, klet.containerManager)
runtimeCache, err := kubecontainer.NewRuntimeCache(containerManager)
......@@ -341,7 +342,7 @@ type Kubelet struct {
networkPlugin network.NetworkPlugin
// Healthy check prober.
prober kubecontainer.Prober
prober prober.Prober
// Container lifecycle handler runner.
handlerRunner kubecontainer.HandlerRunner
......
......@@ -45,8 +45,11 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/metrics"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/prober"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
uexec "github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/volume/host_path"
......@@ -116,7 +119,7 @@ func newTestKubelet(t *testing.T) *TestKubelet {
},
fakeRecorder)
kubelet.containerManager.Puller = &dockertools.FakeDockerPuller{}
kubelet.prober = newProber(nil, kubelet.readinessManager, kubelet.containerRefManager, kubelet.recorder)
kubelet.prober = prober.New(nil, kubelet.readinessManager, kubelet.containerRefManager, kubelet.recorder)
kubelet.handlerRunner = newHandlerRunner(&fakeHTTP{}, &fakeContainerCommandRunner{}, kubelet.containerManager)
kubelet.volumeManager = newVolumeManager()
return &TestKubelet{kubelet, fakeDocker, mockCadvisor, fakeKubeClient, waitGroup, fakeMirrorClient}
......@@ -4317,3 +4320,287 @@ func TestFilterOutTerminatedPods(t *testing.T) {
t.Errorf("expected %#v, got %#v", expected, actual)
}
}
type fakeExecProber struct {
result probe.Result
err error
}
func (p fakeExecProber) Probe(_ uexec.Cmd) (probe.Result, error) {
return p.result, p.err
}
func makeTestKubelet(result probe.Result, err error) *Kubelet {
kl := &Kubelet{
readinessManager: kubecontainer.NewReadinessManager(),
containerRefManager: kubecontainer.NewRefManager(),
}
// TODO(vmarmol): Fix
fakeExec := fakeExecProber{
result: result,
err: err,
}
kl.prober = prober.NewTestProber(fakeExec, kl.readinessManager, kl.containerRefManager, &record.FakeRecorder{})
return kl
}
// TestProbeContainer tests the functionality of probeContainer.
// Test cases are:
//
// No probe.
// Only LivenessProbe.
// Only ReadinessProbe.
// Both probes.
//
// Also, for each probe, there will be several cases covering whether the initial
// delay has passed, whether the probe handler will return Success, Failure,
// Unknown or error.
//
func TestProbeContainer(t *testing.T) {
dc := &docker.APIContainers{
ID: "foobar",
Created: time.Now().Unix(),
}
tests := []struct {
testContainer api.Container
expectError bool
expectedResult probe.Result
expectedReadiness bool
}{
// No probes.
{
testContainer: api.Container{},
expectedResult: probe.Success,
expectedReadiness: true,
},
// Only LivenessProbe.
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: 100},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Failure,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectError: true,
expectedResult: probe.Unknown,
expectedReadiness: false,
},
// Only ReadinessProbe.
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{InitialDelaySeconds: 100},
},
expectedResult: probe.Success,
expectedReadiness: false,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Success,
expectedReadiness: false,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectError: false,
expectedResult: probe.Success,
expectedReadiness: true,
},
// Both LivenessProbe and ReadinessProbe.
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: 100},
ReadinessProbe: &api.Probe{InitialDelaySeconds: 100},
},
expectedResult: probe.Success,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: 100},
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Success,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: -100},
ReadinessProbe: &api.Probe{InitialDelaySeconds: 100},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: -100},
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Failure,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
}
for _, test := range tests {
var kl *Kubelet
if test.expectError {
kl = makeTestKubelet(test.expectedResult, errors.New("error"))
} else {
kl = makeTestKubelet(test.expectedResult, nil)
}
result, err := kl.prober.Probe(&api.Pod{}, api.PodStatus{}, test.testContainer, dc.ID, dc.Created)
if test.expectError && err == nil {
t.Error("Expected error but did no error was returned.")
}
if !test.expectError && err != nil {
t.Errorf("Expected error but got: %v", err)
}
if test.expectedResult != result {
t.Errorf("Expected result was %v but probeContainer() returned %v", test.expectedResult, result)
}
if test.expectedReadiness != kl.readinessManager.GetReadiness(dc.ID) {
t.Errorf("Expected readiness was %v but probeContainer() set %v", test.expectedReadiness, kl.readinessManager.GetReadiness(dc.ID))
}
}
}
......@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
package prober
import (
"fmt"
......@@ -37,7 +37,12 @@ import (
const maxProbeRetries = 3
// prober helps to check the liveness/readiness of a container.
// Prober checks the healthiness of a container.
type Prober interface {
Probe(pod *api.Pod, status api.PodStatus, container api.Container, containerID string, createdAt int64) (probe.Result, error)
}
// Prober helps to check the liveness/readiness of a container.
type prober struct {
exec execprobe.ExecProber
http httprobe.HTTPProber
......@@ -51,11 +56,11 @@ type prober struct {
// NewProber creates a Prober, it takes a command runner and
// several container info managers.
func newProber(
func New(
runner dockertools.ContainerCommandRunner,
readinessManager *kubecontainer.ReadinessManager,
refManager *kubecontainer.RefManager,
recorder record.EventRecorder) kubecontainer.Prober {
recorder record.EventRecorder) Prober {
return &prober{
exec: execprobe.New(),
......@@ -69,6 +74,21 @@ func newProber(
}
}
// New prober for use in tests.
func NewTestProber(
exec execprobe.ExecProber,
readinessManager *kubecontainer.ReadinessManager,
refManager *kubecontainer.RefManager,
recorder record.EventRecorder) Prober {
return &prober{
exec: exec,
readinessManager: readinessManager,
refManager: refManager,
recorder: recorder,
}
}
// Probe checks the liveness/readiness of the given container.
// If the container's liveness probe is unsuccessful, set readiness to false.
// If liveness is successful, do a readiness check and set readiness accordingly.
......
......@@ -14,21 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package kubelet
package prober
import (
"errors"
"testing"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"
"github.com/fsouza/go-dockerclient"
)
func TestFindPortByName(t *testing.T) {
......@@ -137,289 +131,11 @@ func TestGetTCPAddrParts(t *testing.T) {
}
}
type fakeExecProber struct {
type FakeExecProber struct {
result probe.Result
err error
}
func (p fakeExecProber) Probe(_ exec.Cmd) (probe.Result, error) {
func (p FakeExecProber) Probe(_ exec.Cmd) (probe.Result, error) {
return p.result, p.err
}
func makeTestKubelet(result probe.Result, err error) *Kubelet {
kl := &Kubelet{
readinessManager: kubecontainer.NewReadinessManager(),
containerRefManager: kubecontainer.NewRefManager(),
}
kl.prober = &prober{
exec: fakeExecProber{
result: result,
err: err,
},
readinessManager: kl.readinessManager,
refManager: kl.containerRefManager,
recorder: &record.FakeRecorder{},
}
return kl
}
// TestProbeContainer tests the functionality of probeContainer.
// Test cases are:
//
// No probe.
// Only LivenessProbe.
// Only ReadinessProbe.
// Both probes.
//
// Also, for each probe, there will be several cases covering whether the initial
// delay has passed, whether the probe handler will return Success, Failure,
// Unknown or error.
//
func TestProbeContainer(t *testing.T) {
dc := &docker.APIContainers{
ID: "foobar",
Created: time.Now().Unix(),
}
tests := []struct {
testContainer api.Container
expectError bool
expectedResult probe.Result
expectedReadiness bool
}{
// No probes.
{
testContainer: api.Container{},
expectedResult: probe.Success,
expectedReadiness: true,
},
// Only LivenessProbe.
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: 100},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Failure,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectError: true,
expectedResult: probe.Unknown,
expectedReadiness: false,
},
// Only ReadinessProbe.
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{InitialDelaySeconds: 100},
},
expectedResult: probe.Success,
expectedReadiness: false,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Success,
expectedReadiness: false,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
{
testContainer: api.Container{
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectError: false,
expectedResult: probe.Success,
expectedReadiness: true,
},
// Both LivenessProbe and ReadinessProbe.
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: 100},
ReadinessProbe: &api.Probe{InitialDelaySeconds: 100},
},
expectedResult: probe.Success,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: 100},
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Success,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: -100},
ReadinessProbe: &api.Probe{InitialDelaySeconds: 100},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{InitialDelaySeconds: -100},
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Unknown,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
ReadinessProbe: &api.Probe{InitialDelaySeconds: -100},
},
expectedResult: probe.Failure,
expectedReadiness: false,
},
{
testContainer: api.Container{
LivenessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
ReadinessProbe: &api.Probe{
InitialDelaySeconds: -100,
Handler: api.Handler{
Exec: &api.ExecAction{},
},
},
},
expectedResult: probe.Success,
expectedReadiness: true,
},
}
for _, test := range tests {
var kl *Kubelet
if test.expectError {
kl = makeTestKubelet(test.expectedResult, errors.New("error"))
} else {
kl = makeTestKubelet(test.expectedResult, nil)
}
result, err := kl.prober.Probe(&api.Pod{}, api.PodStatus{}, test.testContainer, dc.ID, dc.Created)
if test.expectError && err == nil {
t.Error("Expected error but did no error was returned.")
}
if !test.expectError && err != nil {
t.Errorf("Expected error but got: %v", err)
}
if test.expectedResult != result {
t.Errorf("Expected result was %v but probeContainer() returned %v", test.expectedResult, result)
}
if test.expectedReadiness != kl.readinessManager.GetReadiness(dc.ID) {
t.Errorf("Expected readiness was %v but probeContainer() set %v", test.expectedReadiness, kl.readinessManager.GetReadiness(dc.ID))
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment