5

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?

Tim Hilt
  • 605
  • 5
  • 23

2 Answers2

8

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.

acid_fuji
  • 6,287
  • 7
  • 22
  • Thanks for the answer! That clarifies it very much for me. Right now, I try to `r.Get` the resource, and check the returned error as `if err != nil && errors.IsNotFound(err)`, which has been working reliably to detect, if the resource was deleted. Would this be a good workaround from your point of view? – Tim Hilt May 12 '21 at 07:22
  • 1
    I'm no expert but yes, looks like a good workaround. It's being implemented in similar way [here](https://github.com/kubernetes-sigs/controller-runtime/blob/b704f447ea7c8f7059c6665143a4aa1f6da28328/examples/crd/main.go#L57-L63) so it correct. Please don't forget to leave upvote, if you find this answer helpful. – acid_fuji May 12 '21 at 08:02
  • How would one go about differentiating between create and update within the `Reconcile` (or where is the documentation showing an example of such)? – DanCat Aug 20 '21 at 17:15
  • 3
    @DanCat I think the kubernetes philosophy is if you're asking that question you're doing it wrong. The purpose of a kubernetes controller is to achieve a desired state. It checks the world, and if the world doesn't match that desired state, it does something to bring it closer to the desired state. So it doesn't care what triggered the reconcile - that's history. What matters is right now what do I do to fix whatever is wrong. – Yair Halberstadt Oct 18 '21 at 09:24
0

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/

wow qing
  • 352
  • 4
  • 9
  • You should add some context to this link. Who is this post from? Why should I read it? The text you quoted is talking about another issue entirely, how does that issue relate to the current question? Also what does the `WithEventFilter` function does? – VinGarcia Aug 16 '23 at 17:10