How to create or patch a k8s object from the controller?
Option 1: Use Server-side apply (SSA)
obj := &v1alpha1.SomeResource{
ObjectMeta: metav1.ObjectMeta{
Namespace: "some-namespace",
Name: "some-name",
},
Spec: v1alpha1.SomeResourceSpec{
...
},
}
if err := r.Client().Patch(ctx, obj, client.Apply, client.FieldOwner(reconcilerName)); err != nil {
...
}
Option 2: CreateOrUpdate
The spec should be specified in the mutate function rather than in the object itself. The mutate function is one that modifies the resource to its desired state and will be executed regardless of creating or updating a resource.
obj := &v1alpha1.SomeResource{
ObjectMeta: metav1.ObjectMeta{
Namespace: "some-namespace",
Name: "some-name",
},
}
if _, err := controllerutil.CreateOrUpdate(ctx, r.Client(), obj, func() error {
obj.Spec = v1alpha1.SomeResourceSpec{
...
}
return nil
}); err != nil {
return ctrl.Result{}, err
}
The way CreateOrUpdate (or CreateOrPatch) works is:
- Run a Get() on the passed in obj, which stores the current spec in obj if it exists
- Run the mutate function on obj
- Depending on whether obj exists, run Create() or Update()
So to ensure that the desired state is always updated, you should specify the spec (and any other fields that the controller needs to set) in the mutate function, and only specify the namespace and name before CreateOrUpdate.