skip to Main Content

Im using the following code inside kubebuilder controller to read before update for k8s custom resource, im checking if the object exist if yes check if need to update, if not create it , as I need to use it in several places
I want to ask:

  • if there is some helper that can help me to reduce this boilarplate
    code ? something like createOrUpdate func

  • am I doing it right ?

if err := r.Get(ctx, client.ObjectKey{Name: sCrName, Namespace: sCrNs}, &eCmp); err != nil {
    if apierrors.IsNotFound(err) {
        // If the object does not exist, create a new one
        if err := r.Create(ctx, &eCmp); err != nil {
            return ctrl.Result{}, err
        }
    } else {
        // If there was an error other than 'not found', return the error
        return ctrl.Result{}, err
    }
} else {
    // If the object exists, patch it
    patch := client.MergeFrom(eCmp.DeepCopy())
    if err := r.Patch(ctx, &eCmpp, patch); err != nil {
        return ctrl.Result{}, err
    }
}

if enverything is as recomended please let me know.
I need also to do the stratgic merge but the code doesnt support it

I found the following
https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil#CreateOrUpdate
but I dont want it to be related to timestamp, just if something was change -> update it or something doesnt exist -> create it

2

Answers


  1. you can use the controllerutil.CreateOrUpdate() function from the sigs.k8s.io/controller-runtime/pkg/controller/controllerutil package to reduce boilerplate code.

    use controllerutil.CreateOrUpdate() function:

    if err := controllerutil.CreateOrUpdate(ctx, r.Client, &eCmp, func() error {
        return r.Patch(ctx, &eCmp, client.MergeFrom(eCmp.DeepCopy()))
    }); err != nil {
        return ctrl.Result{}, err
    }
    

    strategic merge, you can add the strategic merge patch to the callback function to patch the object strategically

      if err := controllerutil.CreateOrUpdate(ctx, r.Client, &eCmp, func() error {
            // Create a strategic merge patch
            strategicMergePatch, err := strategicpatch.CreateTwoWayMergePatch(eCmp, &newECmp, eCmp)
            if err != nil {
                return err
            }
        
            // Patch the object strategically
            return r.Patch(ctx, &eCmp, client.ConstantPatch(types.StrategicMergePatchType, strategicMergePatch))
        }); err != nil {
            return ctrl.Result{}, err
        }
    
    Login or Signup to reply.
  2. There isn’t anything wrong with how you’ve done it, you could potentially restructure it a little to reduce the if nesting.

    err := r.Get(ctx, client.ObjectKey{Name: sCrName, Namespace: sCrNs}, &eCmp)
    // Object exists, patch it
    if err == nil {
        patch := client.MergeFrom(eCmp.DeepCopy())
        if err := r.Patch(ctx, &eCmpp, patch); err != nil {
            return ctrl.Result{}, err
        }
        return patch, nil // Adjust appropriately
    } else if apierrors.IsNotFound(err) {
        // Object does not exist, create a new one
        if err := r.Create(ctx, &eCmp); err != nil {
            return ctrl.Result{}, err
        }
    } 
    return ctrl.Result{}, err
    

    That CreateOrUpdate function looks like it should also do what you want. It doesn’t do any comparison with a timestamp. The example on there is doing that specifically but if you look at the underlying function controllerutil.go#L195 you will see that there is no timestamp comparison there.

    What you will need to do is either define your mutate function (a function with the patch logic) and pass that as a parameter or create an anonymous function and pass that in.

    For example:

    op, err := controllerutil.CreateOrUpdate(context.TODO(), client, object, func() error {
        
        // Your mutate logic goes in here
    
        return nil
    })
    

    If you look at the CreateOrUpdate function, it’s essentially doing the same thing you are in your code except for the mutate (patching) of the resource.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search