1/* 2Copyright 2014 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package status 18 19import ( 20 "fmt" 21 "strings" 22 23 "k8s.io/api/core/v1" 24 podutil "k8s.io/kubernetes/pkg/api/v1/pod" 25) 26 27const ( 28 // UnknownContainerStatuses says that all container statuses are unknown. 29 UnknownContainerStatuses = "UnknownContainerStatuses" 30 // PodCompleted says that all related containers have succeeded. 31 PodCompleted = "PodCompleted" 32 // ContainersNotReady says that one or more containers are not ready. 33 ContainersNotReady = "ContainersNotReady" 34 // ContainersNotInitialized says that one or more init containers have not succeeded. 35 ContainersNotInitialized = "ContainersNotInitialized" 36 // ReadinessGatesNotReady says that one or more pod readiness gates are not ready. 37 ReadinessGatesNotReady = "ReadinessGatesNotReady" 38) 39 40// GenerateContainersReadyCondition returns the status of "ContainersReady" condition. 41// The status of "ContainersReady" condition is true when all containers are ready. 42func GenerateContainersReadyCondition(spec *v1.PodSpec, containerStatuses []v1.ContainerStatus, podPhase v1.PodPhase) v1.PodCondition { 43 // Find if all containers are ready or not. 44 if containerStatuses == nil { 45 return v1.PodCondition{ 46 Type: v1.ContainersReady, 47 Status: v1.ConditionFalse, 48 Reason: UnknownContainerStatuses, 49 } 50 } 51 unknownContainers := []string{} 52 unreadyContainers := []string{} 53 for _, container := range spec.Containers { 54 if containerStatus, ok := podutil.GetContainerStatus(containerStatuses, container.Name); ok { 55 if !containerStatus.Ready { 56 unreadyContainers = append(unreadyContainers, container.Name) 57 } 58 } else { 59 unknownContainers = append(unknownContainers, container.Name) 60 } 61 } 62 63 // If all containers are known and succeeded, just return PodCompleted. 64 if podPhase == v1.PodSucceeded && len(unknownContainers) == 0 { 65 return v1.PodCondition{ 66 Type: v1.ContainersReady, 67 Status: v1.ConditionFalse, 68 Reason: PodCompleted, 69 } 70 } 71 72 // Generate message for containers in unknown condition. 73 unreadyMessages := []string{} 74 if len(unknownContainers) > 0 { 75 unreadyMessages = append(unreadyMessages, fmt.Sprintf("containers with unknown status: %s", unknownContainers)) 76 } 77 if len(unreadyContainers) > 0 { 78 unreadyMessages = append(unreadyMessages, fmt.Sprintf("containers with unready status: %s", unreadyContainers)) 79 } 80 unreadyMessage := strings.Join(unreadyMessages, ", ") 81 if unreadyMessage != "" { 82 return v1.PodCondition{ 83 Type: v1.ContainersReady, 84 Status: v1.ConditionFalse, 85 Reason: ContainersNotReady, 86 Message: unreadyMessage, 87 } 88 } 89 90 return v1.PodCondition{ 91 Type: v1.ContainersReady, 92 Status: v1.ConditionTrue, 93 } 94} 95 96// GeneratePodReadyCondition returns "Ready" condition of a pod. 97// The status of "Ready" condition is "True", if all containers in a pod are ready 98// AND all matching conditions specified in the ReadinessGates have status equal to "True". 99func GeneratePodReadyCondition(spec *v1.PodSpec, conditions []v1.PodCondition, containerStatuses []v1.ContainerStatus, podPhase v1.PodPhase) v1.PodCondition { 100 containersReady := GenerateContainersReadyCondition(spec, containerStatuses, podPhase) 101 // If the status of ContainersReady is not True, return the same status, reason and message as ContainersReady. 102 if containersReady.Status != v1.ConditionTrue { 103 return v1.PodCondition{ 104 Type: v1.PodReady, 105 Status: containersReady.Status, 106 Reason: containersReady.Reason, 107 Message: containersReady.Message, 108 } 109 } 110 111 // Evaluate corresponding conditions specified in readiness gate 112 // Generate message if any readiness gate is not satisfied. 113 unreadyMessages := []string{} 114 for _, rg := range spec.ReadinessGates { 115 _, c := podutil.GetPodConditionFromList(conditions, rg.ConditionType) 116 if c == nil { 117 unreadyMessages = append(unreadyMessages, fmt.Sprintf("corresponding condition of pod readiness gate %q does not exist.", string(rg.ConditionType))) 118 } else if c.Status != v1.ConditionTrue { 119 unreadyMessages = append(unreadyMessages, fmt.Sprintf("the status of pod readiness gate %q is not \"True\", but %v", string(rg.ConditionType), c.Status)) 120 } 121 } 122 123 // Set "Ready" condition to "False" if any readiness gate is not ready. 124 if len(unreadyMessages) != 0 { 125 unreadyMessage := strings.Join(unreadyMessages, ", ") 126 return v1.PodCondition{ 127 Type: v1.PodReady, 128 Status: v1.ConditionFalse, 129 Reason: ReadinessGatesNotReady, 130 Message: unreadyMessage, 131 } 132 } 133 134 return v1.PodCondition{ 135 Type: v1.PodReady, 136 Status: v1.ConditionTrue, 137 } 138} 139 140// GeneratePodInitializedCondition returns initialized condition if all init containers in a pod are ready, else it 141// returns an uninitialized condition. 142func GeneratePodInitializedCondition(spec *v1.PodSpec, containerStatuses []v1.ContainerStatus, podPhase v1.PodPhase) v1.PodCondition { 143 // Find if all containers are ready or not. 144 if containerStatuses == nil && len(spec.InitContainers) > 0 { 145 return v1.PodCondition{ 146 Type: v1.PodInitialized, 147 Status: v1.ConditionFalse, 148 Reason: UnknownContainerStatuses, 149 } 150 } 151 unknownContainers := []string{} 152 unreadyContainers := []string{} 153 for _, container := range spec.InitContainers { 154 if containerStatus, ok := podutil.GetContainerStatus(containerStatuses, container.Name); ok { 155 if !containerStatus.Ready { 156 unreadyContainers = append(unreadyContainers, container.Name) 157 } 158 } else { 159 unknownContainers = append(unknownContainers, container.Name) 160 } 161 } 162 163 // If all init containers are known and succeeded, just return PodCompleted. 164 if podPhase == v1.PodSucceeded && len(unknownContainers) == 0 { 165 return v1.PodCondition{ 166 Type: v1.PodInitialized, 167 Status: v1.ConditionTrue, 168 Reason: PodCompleted, 169 } 170 } 171 172 unreadyMessages := []string{} 173 if len(unknownContainers) > 0 { 174 unreadyMessages = append(unreadyMessages, fmt.Sprintf("containers with unknown status: %s", unknownContainers)) 175 } 176 if len(unreadyContainers) > 0 { 177 unreadyMessages = append(unreadyMessages, fmt.Sprintf("containers with incomplete status: %s", unreadyContainers)) 178 } 179 unreadyMessage := strings.Join(unreadyMessages, ", ") 180 if unreadyMessage != "" { 181 return v1.PodCondition{ 182 Type: v1.PodInitialized, 183 Status: v1.ConditionFalse, 184 Reason: ContainersNotInitialized, 185 Message: unreadyMessage, 186 } 187 } 188 189 return v1.PodCondition{ 190 Type: v1.PodInitialized, 191 Status: v1.ConditionTrue, 192 } 193} 194