diff --git a/pkg/api/v1/pod/util.go b/pkg/api/v1/pod/util.go index 9560121bbe5..4ae77d543a2 100644 --- a/pkg/api/v1/pod/util.go +++ b/pkg/api/v1/pod/util.go @@ -301,6 +301,16 @@ func IsPodReady(pod *v1.Pod) bool { return IsPodReadyConditionTrue(pod.Status) } +// IsPodTerminal returns true if a pod is terminal, all containers are stopped and cannot ever regress. +func IsPodTerminal(pod *v1.Pod) bool { + return IsPodPhaseTerminal(pod.Status.Phase) +} + +// IsPhaseTerminal returns true if the pod's phase is terminal. +func IsPodPhaseTerminal(phase v1.PodPhase) bool { + return phase == v1.PodFailed || phase == v1.PodSucceeded +} + // IsPodReadyConditionTrue returns true if a pod is ready; false otherwise. func IsPodReadyConditionTrue(status v1.PodStatus) bool { condition := GetPodReadyCondition(status) diff --git a/pkg/api/v1/pod/util_test.go b/pkg/api/v1/pod/util_test.go index eb0425cf44a..78b1b92f376 100644 --- a/pkg/api/v1/pod/util_test.go +++ b/pkg/api/v1/pod/util_test.go @@ -749,6 +749,48 @@ func TestIsPodAvailable(t *testing.T) { } } +func TestIsPodTerminal(t *testing.T) { + now := metav1.Now() + + tests := []struct { + podPhase v1.PodPhase + expected bool + }{ + { + podPhase: v1.PodFailed, + expected: true, + }, + { + podPhase: v1.PodSucceeded, + expected: true, + }, + { + podPhase: v1.PodUnknown, + expected: false, + }, + { + podPhase: v1.PodPending, + expected: false, + }, + { + podPhase: v1.PodRunning, + expected: false, + }, + { + expected: false, + }, + } + + for i, test := range tests { + pod := newPod(now, true, 0) + pod.Status.Phase = test.podPhase + isTerminal := IsPodTerminal(pod) + if isTerminal != test.expected { + t.Errorf("[tc #%d] expected terminal pod: %t, got: %t", i, test.expected, isTerminal) + } + } +} + func TestGetContainerStatus(t *testing.T) { type ExpectedStruct struct { status v1.ContainerStatus diff --git a/pkg/kubelet/status/status_manager.go b/pkg/kubelet/status/status_manager.go index 377d44b4718..845137e0656 100644 --- a/pkg/kubelet/status/status_manager.go +++ b/pkg/kubelet/status/status_manager.go @@ -859,7 +859,7 @@ func mergePodStatus(oldPodStatus, newPodStatus v1.PodStatus, couldHaveRunningCon // the Kubelet exclusively owns must be released prior to a pod being reported terminal, // while resources that have participanting components above the API use the pod's // transition to a terminal phase (or full deletion) to release those resources. - if !isPhaseTerminal(oldPodStatus.Phase) && isPhaseTerminal(newPodStatus.Phase) { + if !podutil.IsPodPhaseTerminal(oldPodStatus.Phase) && podutil.IsPodPhaseTerminal(newPodStatus.Phase) { if couldHaveRunningContainers { newPodStatus.Phase = oldPodStatus.Phase newPodStatus.Reason = oldPodStatus.Reason @@ -870,11 +870,6 @@ func mergePodStatus(oldPodStatus, newPodStatus v1.PodStatus, couldHaveRunningCon return newPodStatus } -// isPhaseTerminal returns true if the pod's phase is terminal. -func isPhaseTerminal(phase v1.PodPhase) bool { - return phase == v1.PodFailed || phase == v1.PodSucceeded -} - // NeedToReconcilePodReadiness returns if the pod "Ready" condition need to be reconcile func NeedToReconcilePodReadiness(pod *v1.Pod) bool { if len(pod.Spec.ReadinessGates) == 0 {