Getting the type of event, that triggered a controller in kubebuilder

2.1k views Asked by At

I'm just getting started with kubebuilder and Golang to extend our Kubernetes-cluster with a custom resource. I would love to do different things in the reconciler-function based on the event, that actually called it.

Was the resource created? Was it updated? Was it deleted?

Each of those events triggers the controller, however, I can't seem to find a possibility to see, which of those events actually happened. I can work around this issue by writing a reconciler like this:

func (r *ServiceDescriptorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    service := &batchv1.ServiceDescriptor{}
    if err := r.Get(context.TODO(), req.NamespacedName, service); err != nil && errors.IsNotFound(err) {
        fmt.Println("Resource was not found -> must have been deleted")
    else {
        fmt.Println("No errors found -> Resource must have been created or updated")
    }
}

However, this feels oddly implicit and kinda hacky.

Is there a clean (possibly native) way of getting the event-type of the reconciler-call?

2

There are 2 answers

4
acid_fuji On BEST ANSWER

You won't be able to to that because this system was designed as level-based and it's not being triggered by individual events changes but rather by the actual cluster state that is being fetch from the apiserver.

Looking at reconcile.go you will notice in line #84 has this comment about it:

Reconciliation is level-based, meaning action isn't driven off changes in individual Events, but instead is driven by actual cluster state read from the apiserver or a local cache. For example if responding to a Pod Delete Event, the Request won't contain that a Pod was deleted,instead the reconcile function observes this when reading the cluster state and seeing the Pod as missing.

And in line #44:

Request contains the information necessary to reconcile a Kubernetes object. This includes the information to uniquely identify the object - its Name and Namespace. It does NOT contain information about any specific Event or the object contents itself.

1
wow qing On

You can try WithEventFilter(predicate.Funcs{}).

Since the reconiliation loop wasn’t taking any action when invoked after the item is actually deleted the predicate for delete events can simply return false! There is also a handy Funcs type that implements the Predicate interface and allows you to pass in functions you want to use as predicates. Putting it all together to filter out the delete events, we have:

func (r *CronJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&batch.CronJob{}).
        WithEventFilter(predicate.Funcs{
            DeleteFunc: func(e event.DeleteEvent) bool {
                // The reconciler adds a finalizer so we perform clean-up
                // when the delete timestamp is added
                // Suppress Delete events to avoid filtering them out in the Reconcile function
                return false
            },
        }).
        Complete(r) }

https://stuartleeks.com/posts/kubebuilder-event-filters-part-1-delete/