@@ -1616,7 +1616,7 @@ func (kl *Kubelet) convertStatusToAPIStatus(pod *v1.Pod, podStatus *kubecontaine
1616
1616
// convertToAPIContainerStatuses converts the given internal container
1617
1617
// statuses into API container statuses.
1618
1618
func (kl * Kubelet ) convertToAPIContainerStatuses (pod * v1.Pod , podStatus * kubecontainer.PodStatus , previousStatus []v1.ContainerStatus , containers []v1.Container , hasInitContainers , isInitContainer bool ) []v1.ContainerStatus {
1619
- convertContainerStatus := func (cs * kubecontainer.Status ) * v1.ContainerStatus {
1619
+ convertContainerStatus := func (cs * kubecontainer.Status , oldStatus * v1. ContainerStatus ) * v1.ContainerStatus {
1620
1620
cid := cs .ID .String ()
1621
1621
status := & v1.ContainerStatus {
1622
1622
Name : cs .Name ,
@@ -1625,17 +1625,17 @@ func (kl *Kubelet) convertToAPIContainerStatuses(pod *v1.Pod, podStatus *kubecon
1625
1625
ImageID : cs .ImageID ,
1626
1626
ContainerID : cid ,
1627
1627
}
1628
- switch cs . State {
1629
- case kubecontainer .ContainerStateRunning :
1628
+ switch {
1629
+ case cs . State == kubecontainer .ContainerStateRunning :
1630
1630
status .State .Running = & v1.ContainerStateRunning {StartedAt : metav1 .NewTime (cs .StartedAt )}
1631
- case kubecontainer .ContainerStateCreated :
1631
+ case cs . State == kubecontainer .ContainerStateCreated :
1632
1632
// Treat containers in the "created" state as if they are exited.
1633
1633
// The pod workers are supposed start all containers it creates in
1634
1634
// one sync (syncPod) iteration. There should not be any normal
1635
1635
// "created" containers when the pod worker generates the status at
1636
1636
// the beginning of a sync iteration.
1637
1637
fallthrough
1638
- case kubecontainer .ContainerStateExited :
1638
+ case cs . State == kubecontainer .ContainerStateExited :
1639
1639
status .State .Terminated = & v1.ContainerStateTerminated {
1640
1640
ExitCode : int32 (cs .ExitCode ),
1641
1641
Reason : cs .Reason ,
@@ -1644,6 +1644,24 @@ func (kl *Kubelet) convertToAPIContainerStatuses(pod *v1.Pod, podStatus *kubecon
1644
1644
FinishedAt : metav1 .NewTime (cs .FinishedAt ),
1645
1645
ContainerID : cid ,
1646
1646
}
1647
+
1648
+ case cs .State == kubecontainer .ContainerStateUnknown &&
1649
+ oldStatus != nil && // we have an old status
1650
+ oldStatus .State .Running != nil : // our previous status was running
1651
+ // if this happens, then we know that this container was previously running and isn't anymore (assuming the CRI isn't failing to return running containers).
1652
+ // you can imagine this happening in cases where a container failed and the kubelet didn't ask about it in time to see the result.
1653
+ // in this case, the container should not to into waiting state immediately because that can make cases like runonce pods actually run
1654
+ // twice. "container never ran" is different than "container ran and failed". This is handled differently in the kubelet
1655
+ // and it is handled differently in higher order logic like crashloop detection and handling
1656
+ status .State .Terminated = & v1.ContainerStateTerminated {
1657
+ Reason : "ContainerStatusUnknown" ,
1658
+ Message : "The container could not be located when the pod was terminated" ,
1659
+ ExitCode : 137 , // this code indicates an error
1660
+ }
1661
+ // the restart count normally comes from the CRI (see near the top of this method), but since this is being added explicitly
1662
+ // for the case where the CRI did not return a status, we need to manually increment the restart count to be accurate.
1663
+ status .RestartCount = oldStatus .RestartCount + 1
1664
+
1647
1665
default :
1648
1666
// this collapses any unknown state to container waiting. If any container is waiting, then the pod status moves to pending even if it is running.
1649
1667
// if I'm reading this correctly, then any failure to read status on any container results in the entire pod going pending even if the containers
@@ -1767,7 +1785,11 @@ func (kl *Kubelet) convertToAPIContainerStatuses(pod *v1.Pod, podStatus *kubecon
1767
1785
if containerSeen [cName ] >= 2 {
1768
1786
continue
1769
1787
}
1770
- status := convertContainerStatus (cStatus )
1788
+ var oldStatusPtr * v1.ContainerStatus
1789
+ if oldStatus , ok := oldStatuses [cName ]; ok {
1790
+ oldStatusPtr = & oldStatus
1791
+ }
1792
+ status := convertContainerStatus (cStatus , oldStatusPtr )
1771
1793
if containerSeen [cName ] == 0 {
1772
1794
statuses [cName ] = status
1773
1795
} else {
0 commit comments