1 package conditions
2
3 import (
4 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5 "sigs.k8s.io/controller-runtime/pkg/client"
6
7 "edge-infra.dev/pkg/k8s/meta/status"
8 )
9
10
11
12 type Getter interface {
13 client.Object
14 GetConditions() []metav1.Condition
15 }
16
17
18
19 func Get(from Getter, t string) *metav1.Condition {
20 conditions := from.GetConditions()
21 if conditions == nil {
22 return nil
23 }
24
25 for _, condition := range conditions {
26 if condition.Type == t {
27 return &condition
28 }
29 }
30 return nil
31 }
32
33 func GetConditions(from Getter) []metav1.Condition {
34 return from.GetConditions()
35 }
36
37
38 func Has(from Getter, t string) bool {
39 return Get(from, t) != nil
40 }
41
42
43
44 func IsTrue(from Getter, t string) bool {
45 if c := Get(from, t); c != nil {
46 return c.Status == metav1.ConditionTrue
47 }
48 return false
49 }
50
51
52
53 func IsFalse(from Getter, t string) bool {
54 if c := Get(from, t); c != nil {
55 return c.Status == metav1.ConditionFalse
56 }
57 return false
58 }
59
60
61
62 func IsUnknown(from Getter, t string) bool {
63 if c := Get(from, t); c != nil {
64 return c.Status == metav1.ConditionUnknown
65 }
66 return true
67 }
68
69
70
71
72 func IsReady(from Getter) bool {
73 return !IsStalled(from) && !IsReconciling(from) && IsTrue(from, status.ReadyCondition)
74 }
75
76
77
78 func IsStalled(from Getter) bool {
79 return !IsTrue(from, status.ReconcilingCondition) && IsTrue(from, status.StalledCondition)
80 }
81
82
83
84 func IsReconciling(from Getter) bool {
85 return !IsTrue(from, status.StalledCondition) && IsTrue(from, status.ReconcilingCondition)
86 }
87
88
89 func HasAny(from Getter, t []string) bool {
90 for _, ct := range t {
91 if Has(from, ct) {
92 return true
93 }
94 }
95 return false
96 }
97
98
99
100 func GetReason(from Getter, t string) string {
101 if c := Get(from, t); c != nil {
102 return c.Reason
103 }
104 return ""
105 }
106
107
108 func HasReason(from Getter, t, r string) bool {
109 if c := Get(from, t); c != nil {
110 return c.Reason == r
111 }
112 return false
113 }
114
115
116
117 func GetMessage(from Getter, t string) string {
118 if c := Get(from, t); c != nil {
119 return c.Message
120 }
121 return ""
122 }
123
124
125
126 func GetLastTransitionTime(from Getter, t string) *metav1.Time {
127 if c := Get(from, t); c != nil {
128 return &c.LastTransitionTime
129 }
130 return nil
131 }
132
133
134
135 func GetObservedGeneration(from Getter, t string) int64 {
136 if c := Get(from, t); c != nil {
137 return c.ObservedGeneration
138 }
139 return 0
140 }
141
142
143
144
145 func summary(from Getter, t string, options ...MergeOption) *metav1.Condition {
146 conditions := from.GetConditions()
147
148 mergeOpt := &mergeOptions{}
149 for _, o := range options {
150 o(mergeOpt)
151 }
152
153
154
155
156 conditionsInScope := make([]localizedCondition, 0, len(conditions))
157 for i := range conditions {
158 c := conditions[i]
159 if c.Type == t {
160 continue
161 }
162
163 if mergeOpt.conditionTypes != nil {
164 found := false
165 for _, tt := range mergeOpt.conditionTypes {
166 if c.Type == tt {
167 found = true
168 break
169 }
170 }
171 if !found {
172 continue
173 }
174 }
175
176 conditionsInScope = append(conditionsInScope, localizedCondition{
177 Condition: &c,
178 Getter: from,
179 })
180 }
181
182
183
184 if mergeOpt.addStepCounterIfOnlyConditionTypes != nil {
185 for _, c := range conditionsInScope {
186 found := false
187 for _, tt := range mergeOpt.addStepCounterIfOnlyConditionTypes {
188 if c.Type == tt {
189 found = true
190 break
191 }
192 }
193 if !found {
194 mergeOpt.addStepCounter = false
195 break
196 }
197 }
198 }
199
200
201
202
203 if mergeOpt.addStepCounter {
204 mergeOpt.stepCounter = len(conditionsInScope)
205 if mergeOpt.conditionTypes != nil {
206 mergeOpt.stepCounter = len(mergeOpt.conditionTypes)
207 }
208 if mergeOpt.addStepCounterIfOnlyConditionTypes != nil {
209 mergeOpt.stepCounter = len(mergeOpt.addStepCounterIfOnlyConditionTypes)
210 }
211 }
212
213 return merge(conditionsInScope, t, mergeOpt)
214 }
215
216
217 type mirrorOptions struct {
218 fallbackTo *bool
219 fallbackReason string
220 fallbackMessage string
221 }
222
223
224 type MirrorOptions func(*mirrorOptions)
225
226
227
228
229 func WithFallbackValue(fallbackValue bool, reason string, message string) MirrorOptions {
230 return func(c *mirrorOptions) {
231 c.fallbackTo = &fallbackValue
232 c.fallbackReason = reason
233 c.fallbackMessage = message
234 }
235 }
236
237
238
239
240 func mirror(from Getter, targetCondition string, options ...MirrorOptions) *metav1.Condition {
241 mirrorOpt := &mirrorOptions{}
242 for _, o := range options {
243 o(mirrorOpt)
244 }
245
246 condition := Get(from, status.ReadyCondition)
247
248 if mirrorOpt.fallbackTo != nil && condition == nil {
249 switch *mirrorOpt.fallbackTo {
250 case true:
251 condition = TrueCondition(targetCondition, mirrorOpt.fallbackReason, "%s", mirrorOpt.fallbackMessage)
252 case false:
253 condition = FalseCondition(targetCondition, mirrorOpt.fallbackReason, "%s", mirrorOpt.fallbackMessage)
254 }
255 }
256
257 if condition != nil {
258 condition.Type = targetCondition
259 }
260
261 return condition
262 }
263
264
265
266
267
268 func aggregate(from []Getter, targetCondition string, options ...MergeOption) *metav1.Condition {
269 mergeOpt := &mergeOptions{
270 stepCounter: len(from),
271 }
272 for _, o := range options {
273 o(mergeOpt)
274 }
275
276 conditionsInScope := make([]localizedCondition, 0, len(from))
277 for i := range from {
278 conditions := from[i].GetConditions()
279 for i := range conditions {
280 c := conditions[i]
281 if mergeOpt.conditionTypes != nil {
282 found := false
283 for _, tt := range mergeOpt.conditionTypes {
284 if c.Type == tt {
285 found = true
286 break
287 }
288 }
289 if !found {
290 continue
291 }
292 }
293
294 conditionsInScope = append(conditionsInScope, localizedCondition{
295 Condition: &c,
296 Getter: from[i],
297 })
298 }
299 }
300
301
302
303 if mergeOpt.addCounterOnlyIfConditionTypes != nil {
304 for _, c := range conditionsInScope {
305 found := false
306 for _, tt := range mergeOpt.addCounterOnlyIfConditionTypes {
307 if c.Type == tt {
308 found = true
309 break
310 }
311 }
312 if !found {
313 mergeOpt.addCounter = false
314 break
315 }
316 }
317 }
318
319
320
321 if mergeOpt.addSourceRefIfConditionTypes != nil {
322 for _, c := range conditionsInScope {
323 found := false
324 for _, tt := range mergeOpt.addSourceRefIfConditionTypes {
325 if c.Type == tt {
326 found = true
327 break
328 }
329 }
330 if found {
331 mergeOpt.addSourceRef = true
332 break
333 }
334 }
335 }
336
337 return merge(conditionsInScope, targetCondition, mergeOpt)
338 }
339
View as plain text