From 563f2965babfa19ec0ea53a816b629ed02667500 Mon Sep 17 00:00:00 2001 From: Dawn Chen Date: Wed, 8 Apr 2015 11:53:31 -0700 Subject: [PATCH] Populate last terminated container information --- pkg/kubelet/dockertools/manager.go | 16 +++- pkg/kubelet/kubelet.go | 1 + pkg/kubelet/kubelet_test.go | 139 ++++++++++++++++++++++++++++- 3 files changed, 150 insertions(+), 6 deletions(-) diff --git a/pkg/kubelet/dockertools/manager.go b/pkg/kubelet/dockertools/manager.go index 5be562cdabc..a0c889df323 100644 --- a/pkg/kubelet/dockertools/manager.go +++ b/pkg/kubelet/dockertools/manager.go @@ -138,10 +138,11 @@ func (self *DockerManager) inspectContainer(dockerID, containerName, tPath strin reason = inspectResult.State.Error } result.status.State.Termination = &api.ContainerStateTerminated{ - ExitCode: inspectResult.State.ExitCode, - Reason: reason, - StartedAt: util.NewTime(inspectResult.State.StartedAt), - FinishedAt: util.NewTime(inspectResult.State.FinishedAt), + ExitCode: inspectResult.State.ExitCode, + Reason: reason, + StartedAt: util.NewTime(inspectResult.State.StartedAt), + FinishedAt: util.NewTime(inspectResult.State.FinishedAt), + ContainerID: DockerPrefix + dockerID, } if tPath != "" { path, found := inspectResult.Volumes[tPath] @@ -215,6 +216,13 @@ func (self *DockerManager) GetPodStatus(pod *api.Pod) (*api.PodStatus, error) { } // We assume docker return us a list of containers in time order if containerStatus, found := statuses[dockerContainerName]; found { + // Populate last termination state + if containerStatus.LastTerminationState.Termination == nil { + result := self.inspectContainer(value.ID, dockerContainerName, terminationMessagePath) + if result.err == nil && result.status.State.Termination != nil { + containerStatus.LastTerminationState = result.status.State + } + } containerStatus.RestartCount += 1 statuses[dockerContainerName] = containerStatus continue diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index d541a5e0be4..1b4d7b237f1 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -1987,6 +1987,7 @@ func (kl *Kubelet) generatePodStatus(pod *api.Pod) (api.PodStatus, error) { } } podStatus.Conditions = append(podStatus.Conditions, getPodReadyCondition(spec, podStatus.ContainerStatuses)...) + hostIP, err := kl.GetHostIP() if err != nil { glog.Errorf("Cannot get host IP: %v", err) diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index 4217ab56403..25cdc5b3dd6 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -3602,13 +3602,13 @@ func TestSyncPodsWithRestartPolicy(t *testing.T) { }{ { api.RestartPolicyAlways, - []string{"list", "list", "list", "inspect_container", "inspect_container", "inspect_container", "create", "start", "create", "start", "list", "inspect_container", "inspect_container", "inspect_container"}, + []string{"list", "list", "list", "inspect_container", "inspect_container", "inspect_container", "create", "start", "create", "start", "list", "inspect_container", "inspect_container", "inspect_container", "inspect_container", "inspect_container"}, []string{"succeeded", "failed"}, []string{}, }, { api.RestartPolicyOnFailure, - []string{"list", "list", "list", "inspect_container", "inspect_container", "inspect_container", "create", "start", "list", "inspect_container", "inspect_container", "inspect_container"}, + []string{"list", "list", "list", "inspect_container", "inspect_container", "inspect_container", "create", "start", "list", "inspect_container", "inspect_container", "inspect_container", "inspect_container"}, []string{"failed"}, []string{}, }, @@ -3657,3 +3657,138 @@ func TestSyncPodsWithRestartPolicy(t *testing.T) { } } } + +func TestGetPodStatusWithLastTermination(t *testing.T) { + testKubelet := newTestKubelet(t) + testKubelet.fakeCadvisor.On("MachineInfo").Return(&cadvisorApi.MachineInfo{}, nil) + kubelet := testKubelet.kubelet + fakeDocker := testKubelet.fakeDocker + waitGroup := testKubelet.waitGroup + + containers := []api.Container{ + {Name: "succeeded"}, + {Name: "failed"}, + } + + runningAPIContainers := []docker.APIContainers{ + { + // pod infra container + Names: []string{"/k8s_POD_foo_new_12345678_0"}, + ID: "9876", + }, + } + exitedAPIContainers := []docker.APIContainers{ + { + // format is // k8s___ + Names: []string{"/k8s_succeeded." + strconv.FormatUint(dockertools.HashContainer(&containers[0]), 16) + "_foo_new_12345678_0"}, + ID: "1234", + }, + { + // format is // k8s___ + Names: []string{"/k8s_failed." + strconv.FormatUint(dockertools.HashContainer(&containers[1]), 16) + "_foo_new_12345678_0"}, + ID: "5678", + }, + } + + containerMap := map[string]*docker.Container{ + "1234": { + ID: "1234", + Name: "succeeded", + Config: &docker.Config{}, + State: docker.State{ + ExitCode: 0, + StartedAt: time.Now(), + FinishedAt: time.Now(), + }, + }, + "5678": { + ID: "5678", + Name: "failed", + Config: &docker.Config{}, + State: docker.State{ + ExitCode: 42, + StartedAt: time.Now(), + FinishedAt: time.Now(), + }, + }, + } + + tests := []struct { + policy api.RestartPolicy + created []string + stopped []string + lastTerminations []string + }{ + { + api.RestartPolicyAlways, + []string{"succeeded", "failed"}, + []string{}, + []string{"docker://1234", "docker://5678"}, + }, + { + api.RestartPolicyOnFailure, + []string{"failed"}, + []string{}, + []string{"docker://5678"}, + }, + { + api.RestartPolicyNever, + []string{}, + []string{"9876"}, + []string{}, + }, + } + + for i, tt := range tests { + fakeDocker.ContainerList = runningAPIContainers + fakeDocker.ExitedContainerList = exitedAPIContainers + fakeDocker.ContainerMap = containerMap + fakeDocker.ClearCalls() + pods := []api.Pod{ + { + ObjectMeta: api.ObjectMeta{ + UID: "12345678", + Name: "foo", + Namespace: "new", + }, + Spec: api.PodSpec{ + Containers: containers, + RestartPolicy: tt.policy, + }, + }, + } + kubelet.podManager.SetPods(pods) + waitGroup.Add(1) + err := kubelet.SyncPods(pods, emptyPodUIDs, map[string]api.Pod{}, time.Now()) + if err != nil { + t.Errorf("%d: unexpected error: %v", i, err) + } + waitGroup.Wait() + + // Check if we can retrieve the pod status from GetPodStatus(). + podName := kubecontainer.GetPodFullName(&pods[0]) + status, err := kubelet.GetPodStatus(podName) + if err != nil { + t.Fatalf("unable to retrieve pod status for pod %q: %#v.", podName, err) + } else { + terminatedContainers := []string{} + for _, cs := range status.ContainerStatuses { + if cs.LastTerminationState.Termination != nil { + terminatedContainers = append(terminatedContainers, cs.LastTerminationState.Termination.ContainerID) + } + } + sort.StringSlice(terminatedContainers).Sort() + sort.StringSlice(tt.lastTerminations).Sort() + if !reflect.DeepEqual(terminatedContainers, tt.lastTerminations) { + t.Errorf("Expected(sorted): %#v, Actual(sorted): %#v", tt.lastTerminations, terminatedContainers) + } + } + + if err := fakeDocker.AssertCreated(tt.created); err != nil { + t.Errorf("%d: %v", i, err) + } + if err := fakeDocker.AssertStopped(tt.stopped); err != nil { + t.Errorf("%d: %v", i, err) + } + } +}