From 912426b0f54d7383fc98d86dc4afe2b014b69951 Mon Sep 17 00:00:00 2001 From: Andrew McDermott Date: Thu, 26 Oct 2017 15:25:27 +0100 Subject: [PATCH] UPSTREAM: 54597: kubelet: check for illegal container state transition xref kubernetes/kubernetes#54597 --- .../pkg/kubelet/status/status_manager.go | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/status/status_manager.go b/vendor/k8s.io/kubernetes/pkg/kubelet/status/status_manager.go index a2047a8b544e..6b9f3cffd01b 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/status/status_manager.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/status/status_manager.go @@ -17,6 +17,7 @@ limitations under the License. package status import ( + "fmt" "sort" "sync" "time" @@ -273,6 +274,23 @@ func (m *manager) TerminatePod(pod *v1.Pod) { m.updateStatusInternal(pod, status, true) } +// checkContainerStateTransition ensures that no container is trying to transition +// from a terminated to non-terminated state, which is illegal and indicates a +// logical error in the kubelet. +func checkContainerStateTransition(oldStatuses, newStatuses []v1.ContainerStatus) error { + for _, newStatus := range newStatuses { + for _, oldStatus := range oldStatuses { + if newStatus.Name != oldStatus.Name { + continue + } + if oldStatus.State.Terminated != nil && newStatus.State.Terminated == nil { + return fmt.Errorf("terminated container %v attempted illegal transition to non-terminated state", newStatus.Name) + } + } + } + return nil +} + // updateStatusInternal updates the internal status cache, and queues an update to the api server if // necessary. Returns whether an update was triggered. // This method IS NOT THREAD SAFE and must be called from a locked function. @@ -287,6 +305,18 @@ func (m *manager) updateStatusInternal(pod *v1.Pod, status v1.PodStatus, forceUp oldStatus = pod.Status } + // Check for illegal state transition in containers + if pod.Spec.RestartPolicy == v1.RestartPolicyNever { + if err := checkContainerStateTransition(oldStatus.ContainerStatuses, status.ContainerStatuses); err != nil { + glog.Errorf("Status update on pod %v/%v aborted: %v", pod.Namespace, pod.Name, err) + return false + } + if err := checkContainerStateTransition(oldStatus.InitContainerStatuses, status.InitContainerStatuses); err != nil { + glog.Errorf("Status update on pod %v/%v aborted: %v", pod.Namespace, pod.Name, err) + return false + } + } + // Set ReadyCondition.LastTransitionTime. if _, readyCondition := podutil.GetPodCondition(&status, v1.PodReady); readyCondition != nil { // Need to set LastTransitionTime.