Skip to content

Commit 1b1ebc0

Browse files
authored
doc/user/event-filtering.md: event filtering with Predicates (#771)
* doc/user/event-filtering.md: describe event filtering with Predicates
1 parent bd969e2 commit 1b1ebc0

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

doc/user/event-filtering.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Event filtering with Predicates
2+
3+
[Events][doc_event] are produced by [Sources][doc_source] assigned to resources a controller is watching. These events are transformed into Requests by [EventHandlers][doc_eventhandler] and passed to `Reconcile()`. [Predicates][doc_predicate] allow controllers to filter events before they are provided to EventHandlers. Filtering is useful because your controller may only want to handle specific types of events. Filtering also helps reduce chattiness with the API server, as `Reconcile()` is only called for events transformed by EventHandlers.
4+
5+
## Predicate types
6+
7+
A Predicate implements the following methods that take an event of a particular type and return true if the event should be processed by `Reconcile()`:
8+
9+
```Go
10+
// Predicate filters events before enqueuing the keys.
11+
type Predicate interface {
12+
Create(event.CreateEvent) bool
13+
Delete(event.DeleteEvent) bool
14+
Update(event.UpdateEvent) bool
15+
Generic(event.GenericEvent) bool
16+
}
17+
18+
// Funcs implements Predicate.
19+
type Funcs struct {
20+
CreateFunc func(event.CreateEvent) bool
21+
DeleteFunc func(event.DeleteEvent) bool
22+
UpdateFunc func(event.UpdateEvent) bool
23+
GenericFunc func(event.GenericEvent) bool
24+
}
25+
```
26+
27+
For example, all Create events for any watched resource will be passed to `Funcs.Create()` and filtered out if the method evaluates to `false`. If you do not register a Predicate method for a particular type, events of that type will not be filtered.
28+
29+
All event types contain Kubernetes [metadata][doc_object_metadata] about the object that triggered the event, and the object itself. Predicate logic uses these data to make decisions about what should be filtered. Some event types include other fields pertaining to the semantics of that event. For example, `event.UpdateEvent` includes both old and new metadata and objects:
30+
31+
```Go
32+
type UpdateEvent struct {
33+
// MetaOld is the ObjectMeta of the Kubernetes Type that was updated (before the update).
34+
MetaOld v1.Object
35+
36+
// ObjectOld is the object from the event.
37+
ObjectOld runtime.Object
38+
39+
// MetaNew is the ObjectMeta of the Kubernetes Type that was updated (after the update).
40+
MetaNew v1.Object
41+
42+
// ObjectNew is the object from the event.
43+
ObjectNew runtime.Object
44+
}
45+
```
46+
47+
You can find all type definitions in the `event` package [documentation][doc_event].
48+
49+
## Using Predicates
50+
51+
Any number of Predicates can be passed to `controller.Watch()`, which will filter an event if any of those Predicates evaluates to `false`. This first example is an implementation of a `memcached-operator` controller that simply filters Delete events on Pods that have been confirmed deleted; the controller receives all Delete events that occur, and we may only care about resources that have not been completely deleted:
52+
53+
```Go
54+
import (
55+
cachev1alpha1 "github.com/example-inc/app-operator/pkg/apis/cache/v1alpha1"
56+
57+
corev1 "k8s.io/api/core/v1"
58+
"sigs.k8s.io/controller-runtime/pkg/controller"
59+
"sigs.k8s.io/controller-runtime/pkg/event"
60+
"sigs.k8s.io/controller-runtime/pkg/handler"
61+
"sigs.k8s.io/controller-runtime/pkg/manager"
62+
"sigs.k8s.io/controller-runtime/pkg/predicate"
63+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
64+
"sigs.k8s.io/controller-runtime/pkg/source"
65+
)
66+
67+
// add adds a new Controller to mgr with r as the reconcile.Reconciler.
68+
func add(mgr manager.Manager, r reconcile.Reconciler) error {
69+
// Create a new controller.
70+
c, err := controller.New("memcached-controller", mgr, controller.Options{Reconciler: r})
71+
if err != nil {
72+
return err
73+
}
74+
75+
...
76+
77+
// Create a source for watching Pod events.
78+
src := &source.Kind{Type: &corev1.Pod{}}
79+
// Create a handler for handling events from Pods owned by the Memcached resource.
80+
h := &handler.EnqueueRequestForOwner{
81+
IsController: true,
82+
OwnerType: &cachev1alpha1.Memcached{},
83+
}
84+
pred := predicate.Funcs{
85+
UpdateFunc: func(e event.UpdateEvent) bool {
86+
// Ignore updates to CR status in which case metadata.Generation does not change
87+
return e.MetaOld.GetGeneration() != e.MetaNew.GetGeneration()
88+
},
89+
DeleteFunc: func(e event.DeleteEvent) bool {
90+
// Evaluates to false if the object has been confirmed deleted.
91+
return !e.DeleteStateUnknown
92+
},
93+
}
94+
// Watch for Pod events.
95+
err = c.Watch(src, h, pred)
96+
if err != nil {
97+
return err
98+
}
99+
100+
...
101+
}
102+
```
103+
104+
## Use cases
105+
106+
Predicates are not necessary for many operators, although filtering reduces the amount of chatter to the API server from `Reconcile()`. They are particularly useful for controllers that watch resources cluster-wide, i.e. without a namespace.
107+
108+
[doc_event]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/event
109+
[doc_source]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/source#Source
110+
[doc_eventhandler]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/handler#EventHandler
111+
[doc_predicate]:https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/predicate
112+
[doc_object_metadata]:https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1#Object

0 commit comments

Comments
 (0)