...
1
16
17 package podutils
18
19 import (
20 "time"
21
22 corev1 "k8s.io/api/core/v1"
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 )
25
26
27
28
29
30
31 func IsPodAvailable(pod *corev1.Pod, minReadySeconds int32, now metav1.Time) bool {
32 if !IsPodReady(pod) {
33 return false
34 }
35
36 c := getPodReadyCondition(pod.Status)
37 minReadySecondsDuration := time.Duration(minReadySeconds) * time.Second
38 if minReadySeconds == 0 || !c.LastTransitionTime.IsZero() && c.LastTransitionTime.Add(minReadySecondsDuration).Before(now.Time) {
39 return true
40 }
41 return false
42 }
43
44
45 func IsPodReady(pod *corev1.Pod) bool {
46 return isPodReadyConditionTrue(pod.Status)
47 }
48
49 func isPodDeleting(pod *corev1.Pod) bool {
50 return pod.DeletionTimestamp != nil
51 }
52
53
54 func isPodReadyConditionTrue(status corev1.PodStatus) bool {
55 condition := getPodReadyCondition(status)
56 return condition != nil && condition.Status == corev1.ConditionTrue
57 }
58
59
60
61 func getPodReadyCondition(status corev1.PodStatus) *corev1.PodCondition {
62 _, condition := getPodCondition(&status, corev1.PodReady)
63 return condition
64 }
65
66
67
68 func getPodCondition(status *corev1.PodStatus, conditionType corev1.PodConditionType) (int, *corev1.PodCondition) {
69 if status == nil {
70 return -1, nil
71 }
72 return getPodConditionFromList(status.Conditions, conditionType)
73 }
74
75
76
77 func getPodConditionFromList(conditions []corev1.PodCondition, conditionType corev1.PodConditionType) (int, *corev1.PodCondition) {
78 if conditions == nil {
79 return -1, nil
80 }
81 for i := range conditions {
82 if conditions[i].Type == conditionType {
83 return i, &conditions[i]
84 }
85 }
86 return -1, nil
87 }
88
89
90 type ByLogging []*corev1.Pod
91
92 func (s ByLogging) Len() int { return len(s) }
93 func (s ByLogging) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
94
95 func (s ByLogging) Less(i, j int) bool {
96
97 if s[i].Spec.NodeName != s[j].Spec.NodeName && (len(s[i].Spec.NodeName) == 0 || len(s[j].Spec.NodeName) == 0) {
98 return len(s[i].Spec.NodeName) > 0
99 }
100
101 m := map[corev1.PodPhase]int{corev1.PodRunning: 0, corev1.PodUnknown: 1, corev1.PodPending: 2}
102 if m[s[i].Status.Phase] != m[s[j].Status.Phase] {
103 return m[s[i].Status.Phase] < m[s[j].Status.Phase]
104 }
105
106 if IsPodReady(s[i]) != IsPodReady(s[j]) {
107 return IsPodReady(s[i])
108 }
109
110
111
112 if IsPodReady(s[i]) && IsPodReady(s[j]) && !podReadyTime(s[i]).Equal(podReadyTime(s[j])) {
113 return afterOrZero(podReadyTime(s[j]), podReadyTime(s[i]))
114 }
115
116 if maxContainerRestarts(s[i]) != maxContainerRestarts(s[j]) {
117 return maxContainerRestarts(s[i]) > maxContainerRestarts(s[j])
118 }
119
120 if !s[i].CreationTimestamp.Equal(&s[j].CreationTimestamp) {
121 return afterOrZero(&s[j].CreationTimestamp, &s[i].CreationTimestamp)
122 }
123 return false
124 }
125
126
127 type ActivePods []*corev1.Pod
128
129 func (s ActivePods) Len() int { return len(s) }
130 func (s ActivePods) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
131
132 func (s ActivePods) Less(i, j int) bool {
133
134
135 if s[i].Spec.NodeName != s[j].Spec.NodeName && (len(s[i].Spec.NodeName) == 0 || len(s[j].Spec.NodeName) == 0) {
136 return len(s[i].Spec.NodeName) == 0
137 }
138
139 m := map[corev1.PodPhase]int{corev1.PodPending: 0, corev1.PodUnknown: 1, corev1.PodRunning: 2}
140 if m[s[i].Status.Phase] != m[s[j].Status.Phase] {
141 return m[s[i].Status.Phase] < m[s[j].Status.Phase]
142 }
143
144
145 if IsPodReady(s[i]) != IsPodReady(s[j]) {
146 return !IsPodReady(s[i])
147 }
148
149 if isPodDeleting(s[i]) != isPodDeleting(s[j]) {
150 return isPodDeleting(s[i])
151 }
152
153 if isPodDeleting(s[i]) && isPodDeleting(s[j]) && !s[i].ObjectMeta.DeletionTimestamp.Equal(s[j].ObjectMeta.DeletionTimestamp) {
154 return s[i].ObjectMeta.DeletionTimestamp.Before(s[j].ObjectMeta.DeletionTimestamp)
155 }
156
157
158
159
160 if IsPodReady(s[i]) && IsPodReady(s[j]) && !podReadyTime(s[i]).Equal(podReadyTime(s[j])) {
161 return afterOrZero(podReadyTime(s[i]), podReadyTime(s[j]))
162 }
163
164 if maxContainerRestarts(s[i]) != maxContainerRestarts(s[j]) {
165 return maxContainerRestarts(s[i]) > maxContainerRestarts(s[j])
166 }
167
168 if !s[i].CreationTimestamp.Equal(&s[j].CreationTimestamp) {
169 return afterOrZero(&s[i].CreationTimestamp, &s[j].CreationTimestamp)
170 }
171 return false
172 }
173
174
175
176 func afterOrZero(t1, t2 *metav1.Time) bool {
177 if t1.Time.IsZero() || t2.Time.IsZero() {
178 return t1.Time.IsZero()
179 }
180 return t1.After(t2.Time)
181 }
182
183 func podReadyTime(pod *corev1.Pod) *metav1.Time {
184 for _, c := range pod.Status.Conditions {
185
186 if c.Type == corev1.PodReady && c.Status == corev1.ConditionTrue {
187 return &c.LastTransitionTime
188 }
189 }
190 return &metav1.Time{}
191 }
192
193 func maxContainerRestarts(pod *corev1.Pod) int {
194 maxRestarts := 0
195 for _, c := range pod.Status.ContainerStatuses {
196 maxRestarts = max(maxRestarts, int(c.RestartCount))
197 }
198 return maxRestarts
199 }
200
201
202
203
204
205
206 type ContainerType int
207
208 const (
209
210 Containers ContainerType = 1 << iota
211
212 InitContainers
213
214 EphemeralContainers
215 )
216
217
218 const AllContainers ContainerType = (InitContainers | Containers | EphemeralContainers)
219
220
221
222 type ContainerVisitor func(container *corev1.Container, containerType ContainerType) (shouldContinue bool)
223
224
225
226
227
228 func VisitContainers(podSpec *corev1.PodSpec, mask ContainerType, visitor ContainerVisitor) bool {
229 if mask&InitContainers != 0 {
230 for i := range podSpec.InitContainers {
231 if !visitor(&podSpec.InitContainers[i], InitContainers) {
232 return false
233 }
234 }
235 }
236 if mask&Containers != 0 {
237 for i := range podSpec.Containers {
238 if !visitor(&podSpec.Containers[i], Containers) {
239 return false
240 }
241 }
242 }
243 if mask&EphemeralContainers != 0 {
244 for i := range podSpec.EphemeralContainers {
245 if !visitor((*corev1.Container)(&podSpec.EphemeralContainers[i].EphemeralContainerCommon), EphemeralContainers) {
246 return false
247 }
248 }
249 }
250 return true
251 }
252
View as plain text