1
16
17 package predicate
18
19 import (
20 "maps"
21 "reflect"
22
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 "k8s.io/apimachinery/pkg/labels"
25 "sigs.k8s.io/controller-runtime/pkg/client"
26 "sigs.k8s.io/controller-runtime/pkg/event"
27 logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
28 )
29
30 var log = logf.RuntimeLog.WithName("predicate").WithName("eventFilters")
31
32
33 type Predicate = TypedPredicate[client.Object]
34
35
36 type TypedPredicate[T any] interface {
37
38 Create(event.TypedCreateEvent[T]) bool
39
40
41 Delete(event.TypedDeleteEvent[T]) bool
42
43
44 Update(event.TypedUpdateEvent[T]) bool
45
46
47 Generic(event.TypedGenericEvent[T]) bool
48 }
49
50 var _ Predicate = Funcs{}
51 var _ Predicate = ResourceVersionChangedPredicate{}
52 var _ Predicate = GenerationChangedPredicate{}
53 var _ Predicate = AnnotationChangedPredicate{}
54 var _ Predicate = or[client.Object]{}
55 var _ Predicate = and[client.Object]{}
56 var _ Predicate = not[client.Object]{}
57
58
59 type Funcs = TypedFuncs[client.Object]
60
61
62 type TypedFuncs[T any] struct {
63
64 CreateFunc func(event.TypedCreateEvent[T]) bool
65
66
67 DeleteFunc func(event.TypedDeleteEvent[T]) bool
68
69
70 UpdateFunc func(event.TypedUpdateEvent[T]) bool
71
72
73 GenericFunc func(event.TypedGenericEvent[T]) bool
74 }
75
76
77 func (p TypedFuncs[T]) Create(e event.TypedCreateEvent[T]) bool {
78 if p.CreateFunc != nil {
79 return p.CreateFunc(e)
80 }
81 return true
82 }
83
84
85 func (p TypedFuncs[T]) Delete(e event.TypedDeleteEvent[T]) bool {
86 if p.DeleteFunc != nil {
87 return p.DeleteFunc(e)
88 }
89 return true
90 }
91
92
93 func (p TypedFuncs[T]) Update(e event.TypedUpdateEvent[T]) bool {
94 if p.UpdateFunc != nil {
95 return p.UpdateFunc(e)
96 }
97 return true
98 }
99
100
101 func (p TypedFuncs[T]) Generic(e event.TypedGenericEvent[T]) bool {
102 if p.GenericFunc != nil {
103 return p.GenericFunc(e)
104 }
105 return true
106 }
107
108
109
110
111 func NewPredicateFuncs(filter func(object client.Object) bool) Funcs {
112 return Funcs{
113 CreateFunc: func(e event.CreateEvent) bool {
114 return filter(e.Object)
115 },
116 UpdateFunc: func(e event.UpdateEvent) bool {
117 return filter(e.ObjectNew)
118 },
119 DeleteFunc: func(e event.DeleteEvent) bool {
120 return filter(e.Object)
121 },
122 GenericFunc: func(e event.GenericEvent) bool {
123 return filter(e.Object)
124 },
125 }
126 }
127
128
129
130
131 func NewTypedPredicateFuncs[T any](filter func(object T) bool) TypedFuncs[T] {
132 return TypedFuncs[T]{
133 CreateFunc: func(e event.TypedCreateEvent[T]) bool {
134 return filter(e.Object)
135 },
136 UpdateFunc: func(e event.TypedUpdateEvent[T]) bool {
137 return filter(e.ObjectNew)
138 },
139 DeleteFunc: func(e event.TypedDeleteEvent[T]) bool {
140 return filter(e.Object)
141 },
142 GenericFunc: func(e event.TypedGenericEvent[T]) bool {
143 return filter(e.Object)
144 },
145 }
146 }
147
148
149 type ResourceVersionChangedPredicate struct {
150 Funcs
151 }
152
153
154 func (ResourceVersionChangedPredicate) Update(e event.UpdateEvent) bool {
155 if e.ObjectOld == nil {
156 log.Error(nil, "Update event has no old object to update", "event", e)
157 return false
158 }
159 if e.ObjectNew == nil {
160 log.Error(nil, "Update event has no new object to update", "event", e)
161 return false
162 }
163
164 return e.ObjectNew.GetResourceVersion() != e.ObjectOld.GetResourceVersion()
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 type GenerationChangedPredicate = TypedGenerationChangedPredicate[client.Object]
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201 type TypedGenerationChangedPredicate[T metav1.Object] struct {
202 TypedFuncs[T]
203 }
204
205
206 func (TypedGenerationChangedPredicate[T]) Update(e event.TypedUpdateEvent[T]) bool {
207 if isNil(e.ObjectOld) {
208 log.Error(nil, "Update event has no old object to update", "event", e)
209 return false
210 }
211 if isNil(e.ObjectNew) {
212 log.Error(nil, "Update event has no new object for update", "event", e)
213 return false
214 }
215
216 return e.ObjectNew.GetGeneration() != e.ObjectOld.GetGeneration()
217 }
218
219
220
221
222
223
224
225
226
227
228
229
230
231 type AnnotationChangedPredicate = TypedAnnotationChangedPredicate[client.Object]
232
233
234 type TypedAnnotationChangedPredicate[T metav1.Object] struct {
235 TypedFuncs[T]
236 }
237
238
239 func (TypedAnnotationChangedPredicate[T]) Update(e event.TypedUpdateEvent[T]) bool {
240 if isNil(e.ObjectOld) {
241 log.Error(nil, "Update event has no old object to update", "event", e)
242 return false
243 }
244 if isNil(e.ObjectNew) {
245 log.Error(nil, "Update event has no new object for update", "event", e)
246 return false
247 }
248
249 return !maps.Equal(e.ObjectNew.GetAnnotations(), e.ObjectOld.GetAnnotations())
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265 type LabelChangedPredicate = TypedLabelChangedPredicate[client.Object]
266
267
268 type TypedLabelChangedPredicate[T metav1.Object] struct {
269 TypedFuncs[T]
270 }
271
272
273 func (TypedLabelChangedPredicate[T]) Update(e event.TypedUpdateEvent[T]) bool {
274 if isNil(e.ObjectOld) {
275 log.Error(nil, "Update event has no old object to update", "event", e)
276 return false
277 }
278 if isNil(e.ObjectNew) {
279 log.Error(nil, "Update event has no new object for update", "event", e)
280 return false
281 }
282
283 return !maps.Equal(e.ObjectNew.GetLabels(), e.ObjectOld.GetLabels())
284 }
285
286
287 func And[T any](predicates ...TypedPredicate[T]) TypedPredicate[T] {
288 return and[T]{predicates}
289 }
290
291 type and[T any] struct {
292 predicates []TypedPredicate[T]
293 }
294
295 func (a and[T]) Create(e event.TypedCreateEvent[T]) bool {
296 for _, p := range a.predicates {
297 if !p.Create(e) {
298 return false
299 }
300 }
301 return true
302 }
303
304 func (a and[T]) Update(e event.TypedUpdateEvent[T]) bool {
305 for _, p := range a.predicates {
306 if !p.Update(e) {
307 return false
308 }
309 }
310 return true
311 }
312
313 func (a and[T]) Delete(e event.TypedDeleteEvent[T]) bool {
314 for _, p := range a.predicates {
315 if !p.Delete(e) {
316 return false
317 }
318 }
319 return true
320 }
321
322 func (a and[T]) Generic(e event.TypedGenericEvent[T]) bool {
323 for _, p := range a.predicates {
324 if !p.Generic(e) {
325 return false
326 }
327 }
328 return true
329 }
330
331
332 func Or[T any](predicates ...TypedPredicate[T]) TypedPredicate[T] {
333 return or[T]{predicates}
334 }
335
336 type or[T any] struct {
337 predicates []TypedPredicate[T]
338 }
339
340 func (o or[T]) Create(e event.TypedCreateEvent[T]) bool {
341 for _, p := range o.predicates {
342 if p.Create(e) {
343 return true
344 }
345 }
346 return false
347 }
348
349 func (o or[T]) Update(e event.TypedUpdateEvent[T]) bool {
350 for _, p := range o.predicates {
351 if p.Update(e) {
352 return true
353 }
354 }
355 return false
356 }
357
358 func (o or[T]) Delete(e event.TypedDeleteEvent[T]) bool {
359 for _, p := range o.predicates {
360 if p.Delete(e) {
361 return true
362 }
363 }
364 return false
365 }
366
367 func (o or[T]) Generic(e event.TypedGenericEvent[T]) bool {
368 for _, p := range o.predicates {
369 if p.Generic(e) {
370 return true
371 }
372 }
373 return false
374 }
375
376
377 func Not[T any](predicate TypedPredicate[T]) TypedPredicate[T] {
378 return not[T]{predicate}
379 }
380
381 type not[T any] struct {
382 predicate TypedPredicate[T]
383 }
384
385 func (n not[T]) Create(e event.TypedCreateEvent[T]) bool {
386 return !n.predicate.Create(e)
387 }
388
389 func (n not[T]) Update(e event.TypedUpdateEvent[T]) bool {
390 return !n.predicate.Update(e)
391 }
392
393 func (n not[T]) Delete(e event.TypedDeleteEvent[T]) bool {
394 return !n.predicate.Delete(e)
395 }
396
397 func (n not[T]) Generic(e event.TypedGenericEvent[T]) bool {
398 return !n.predicate.Generic(e)
399 }
400
401
402
403 func LabelSelectorPredicate(s metav1.LabelSelector) (Predicate, error) {
404 selector, err := metav1.LabelSelectorAsSelector(&s)
405 if err != nil {
406 return Funcs{}, err
407 }
408 return NewPredicateFuncs(func(o client.Object) bool {
409 return selector.Matches(labels.Set(o.GetLabels()))
410 }), nil
411 }
412
413 func isNil(arg any) bool {
414 if v := reflect.ValueOf(arg); !v.IsValid() || ((v.Kind() == reflect.Ptr ||
415 v.Kind() == reflect.Interface ||
416 v.Kind() == reflect.Slice ||
417 v.Kind() == reflect.Map ||
418 v.Kind() == reflect.Chan ||
419 v.Kind() == reflect.Func) && v.IsNil()) {
420 return true
421 }
422 return false
423 }
424
View as plain text