Skip to content

Commit c38593b

Browse files
committed
Use Patch operation for CnsVolumeMetadata and CnsFileAccessConfig updates
1 parent 581ed52 commit c38593b

File tree

5 files changed

+551
-14
lines changed

5 files changed

+551
-14
lines changed

pkg/kubernetes/kubernetes.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ package kubernetes
1919
import (
2020
"context"
2121
"embed"
22+
"encoding/json"
2223
"flag"
2324
"fmt"
2425
"net"
2526
"os"
2627
"strconv"
2728
"time"
2829

30+
jsonpatch "github.com/evanphx/json-patch/v5"
2931
vmoperatorv1alpha1 "github.com/vmware-tanzu/vm-operator/api/v1alpha1"
3032
vmoperatortypes "github.com/vmware-tanzu/vm-operator/api/v1alpha2"
3133
v1 "k8s.io/api/core/v1"
@@ -37,6 +39,7 @@ import (
3739
"k8s.io/apimachinery/pkg/runtime"
3840
"k8s.io/apimachinery/pkg/runtime/schema"
3941
"k8s.io/apimachinery/pkg/runtime/serializer"
42+
apitypes "k8s.io/apimachinery/pkg/types"
4043
"k8s.io/apimachinery/pkg/util/wait"
4144
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
4245
clientset "k8s.io/client-go/kubernetes"
@@ -827,3 +830,46 @@ func RemoveFinalizer(ctx context.Context, c client.Client, obj client.Object, fi
827830
log.Info("Removing finalizer from object.")
828831
return c.Update(ctx, obj)
829832
}
833+
834+
// PatchObject patches a Kubernetes object using strategic merge patch.
835+
// This function creates a patch between the original and modified objects and applies it using the client.
836+
// It returns an error if the patch operation fails.
837+
func PatchObject(ctx context.Context, k8sClient client.Client, original, modified client.Object) error {
838+
log := logger.GetLogger(ctx)
839+
840+
// Marshal the original object
841+
oldData, err := json.Marshal(original)
842+
if err != nil {
843+
log.Errorf("PatchObject: Failed to marshal original object %s/%s: %v",
844+
original.GetNamespace(), original.GetName(), err)
845+
return err
846+
}
847+
848+
// Marshal the modified object
849+
newData, err := json.Marshal(modified)
850+
if err != nil {
851+
log.Errorf("PatchObject: Failed to marshal modified object %s/%s: %v",
852+
modified.GetNamespace(), modified.GetName(), err)
853+
return err
854+
}
855+
856+
// Create merge patch (compatible with both native K8s resources and CRDs)
857+
patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData)
858+
if err != nil {
859+
log.Errorf("PatchObject: Error creating merge patch for object %s/%s: %v",
860+
original.GetNamespace(), original.GetName(), err)
861+
return err
862+
}
863+
864+
// Apply the patch
865+
patch := client.RawPatch(apitypes.MergePatchType, patchBytes)
866+
if err := k8sClient.Patch(ctx, original, patch); err != nil {
867+
log.Errorf("PatchObject: Failed to patch object %s/%s: %v",
868+
original.GetNamespace(), original.GetName(), err)
869+
return err
870+
}
871+
872+
log.Debugf("PatchObject: Successfully patched object %s/%s",
873+
original.GetNamespace(), original.GetName())
874+
return nil
875+
}

pkg/syncer/cnsoperator/controller/cnsfileaccessconfig/cnsfileaccessconfig_controller.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -526,12 +526,13 @@ func addPvcFinalizer(ctx context.Context,
526526
return nil
527527
}
528528

529+
original := pvc.DeepCopy()
529530
if !controllerutil.AddFinalizer(pvc, cnsoperatortypes.CNSPvcFinalizer) {
530531
return fmt.Errorf("failed to add CNS finalizer to PVC %s in namespace %s", pvc.Name,
531532
pvc.Namespace)
532533
}
533534

534-
err = client.Update(ctx, pvc)
535+
err = k8s.PatchObject(ctx, client, original, pvc)
535536
if err != nil {
536537
return fmt.Errorf("failed to add finalizer %s on PVC %s in namespace %s", cnsoperatortypes.CNSPvcFinalizer,
537538
instance.Spec.PvcName, instance.Namespace)
@@ -597,14 +598,15 @@ func removeFinalizerFromPVC(ctx context.Context, client client.Client,
597598
return nil
598599
}
599600

601+
original := pvc.DeepCopy()
600602
if !controllerutil.RemoveFinalizer(pvc, cnsoperatortypes.CNSPvcFinalizer) {
601603
err := fmt.Errorf("failed to remove finalizer %s from PVC %s in namespace %s",
602604
cnsoperatortypes.CNSPvcFinalizer, pvcName, pvc.Namespace)
603605
log.Errorf("failed to remove finalizer from PVC. Err: %+v", err)
604606
return err
605607
}
606608

607-
err = client.Update(ctx, pvc)
609+
err = k8s.PatchObject(ctx, client, original, pvc)
608610
if err != nil {
609611
return fmt.Errorf("failed to remove finalizer %s from PVC %s in namespace %s",
610612
cnsoperatortypes.CNSPvcFinalizer, pvcName, pvc.Namespace)
@@ -872,9 +874,10 @@ func setInstanceError(ctx context.Context, r *ReconcileCnsFileAccessConfig,
872874
func updateCnsFileAccessConfig(ctx context.Context, client client.Client,
873875
instance *v1a1.CnsFileAccessConfig) error {
874876
log := logger.GetLogger(ctx)
875-
err := client.Update(ctx, instance)
877+
original := instance.DeepCopy()
878+
err := k8s.PatchObject(ctx, client, original, instance)
876879
if err != nil {
877-
log.Errorf("failed to update CnsFileAccessConfig instance: %q on namespace: %q. Error: %+v",
880+
log.Errorf("failed to patch CnsFileAccessConfig instance: %q on namespace: %q. Error: %+v",
878881
instance.Name, instance.Namespace, err)
879882
}
880883
return err

pkg/syncer/cnsoperator/controller/cnsvolumemetadata/cnsvolumemetadata_controller.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import (
2828
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/csi/service/common"
2929
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/csi/service/common/commonco"
3030
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/csi/service/logger"
31-
"sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer/cnsoperator/util"
31+
k8s "sigs.k8s.io/vsphere-csi-driver/v3/pkg/kubernetes"
32+
cnsoperatorutil "sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer/cnsoperator/util"
3233

3334
"github.com/davecgh/go-spew/spew"
3435
v1 "k8s.io/api/core/v1"
@@ -55,7 +56,6 @@ import (
5556
volumes "sigs.k8s.io/vsphere-csi-driver/v3/pkg/common/cns-lib/volume"
5657
cnsvsphere "sigs.k8s.io/vsphere-csi-driver/v3/pkg/common/cns-lib/vsphere"
5758
csitypes "sigs.k8s.io/vsphere-csi-driver/v3/pkg/csi/types"
58-
k8s "sigs.k8s.io/vsphere-csi-driver/v3/pkg/kubernetes"
5959
cnsoperatortypes "sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer/cnsoperator/types"
6060
)
6161

@@ -113,7 +113,7 @@ func newReconciler(mgr manager.Manager, configInfo *commonconfig.ConfigurationIn
113113
// add adds a new Controller to mgr with r as the reconcile.Reconciler.
114114
func add(mgr manager.Manager, r reconcile.Reconciler) error {
115115
ctx, log := logger.GetNewContextWithLogger()
116-
maxWorkerThreads := util.GetMaxWorkerThreads(ctx,
116+
maxWorkerThreads := cnsoperatorutil.GetMaxWorkerThreads(ctx,
117117
workerThreadsEnvVar, defaultMaxWorkerThreads)
118118
// Create a new controller.
119119
c, err := controller.New("cnsvolumemetadata-controller", mgr,
@@ -233,8 +233,9 @@ func (r *ReconcileCnsVolumeMetadata) Reconcile(ctx context.Context,
233233
instance.Spec.EntityName, instance.Spec.EntityType, instance.Spec.GuestClusterID)
234234
recordEvent(ctx, r, instance, v1.EventTypeWarning, msg)
235235
// Update instance.status fields with the errors per volume.
236-
if err = r.client.Update(ctx, instance); err != nil {
237-
msg := fmt.Sprintf("ReconcileCnsVolumeMetadata: Failed to update status for %q. "+
236+
original := instance.DeepCopy()
237+
if err = k8s.PatchObject(ctx, r.client, original, instance); err != nil {
238+
msg := fmt.Sprintf("ReconcileCnsVolumeMetadata: Failed to patch status for %q. "+
238239
"Err: %v.", instance.Name, err)
239240
recordEvent(ctx, r, instance, v1.EventTypeWarning, msg)
240241
}
@@ -246,8 +247,9 @@ func (r *ReconcileCnsVolumeMetadata) Reconcile(ctx context.Context,
246247
for index, finalizer := range instance.Finalizers {
247248
if finalizer == cnsoperatortypes.CNSFinalizer {
248249
log.Debugf("ReconcileCnsVolumeMetadata: Removing finalizer %q for instance %q", finalizer, instance.Name)
250+
original := instance.DeepCopy()
249251
instance.Finalizers = append(instance.Finalizers[:index], instance.Finalizers[index+1:]...)
250-
if err = r.client.Update(ctx, instance); err != nil {
252+
if err = k8s.PatchObject(ctx, r.client, original, instance); err != nil {
251253
msg := fmt.Sprintf("ReconcileCnsVolumeMetadata: Failed to remove finalizer %q for %q. "+
252254
"Err: %v. Requeueing request.", finalizer, instance.Name, err)
253255
recordEvent(ctx, r, instance, v1.EventTypeWarning, msg)
@@ -276,8 +278,9 @@ func (r *ReconcileCnsVolumeMetadata) Reconcile(ctx context.Context,
276278

277279
// Set finalizer if it was not set already on this instance.
278280
if !isFinalizerSet {
281+
original := instance.DeepCopy()
279282
instance.Finalizers = append(instance.Finalizers, cnsoperatortypes.CNSFinalizer)
280-
if err = r.client.Update(ctx, instance); err != nil {
283+
if err = k8s.PatchObject(ctx, r.client, original, instance); err != nil {
281284
msg := fmt.Sprintf("ReconcileCnsVolumeMetadata: Failed to add finalizer %q for %q. "+
282285
"Err: %v. Requeueing request.", cnsoperatortypes.CNSFinalizer, instance.Name, err)
283286
recordEvent(ctx, r, instance, v1.EventTypeWarning, msg)
@@ -293,7 +296,8 @@ func (r *ReconcileCnsVolumeMetadata) Reconcile(ctx context.Context,
293296
recordEvent(ctx, r, instance, v1.EventTypeWarning, msg)
294297
// Update instance.status fields on supervisor API server and requeue
295298
// the request.
296-
_ = r.client.Update(ctx, instance)
299+
original := instance.DeepCopy()
300+
_ = k8s.PatchObject(ctx, r.client, original, instance)
297301
return reconcile.Result{RequeueAfter: timeout}, nil
298302
}
299303
// Successfully updated CNS.
@@ -302,8 +306,9 @@ func (r *ReconcileCnsVolumeMetadata) Reconcile(ctx context.Context,
302306
instance.Spec.EntityName, instance.Spec.EntityType, instance.Spec.GuestClusterID)
303307
recordEvent(ctx, r, instance, v1.EventTypeNormal, msg)
304308
// Update instance.status fields on supervisor API server.
305-
if err = r.client.Update(ctx, instance); err != nil {
306-
msg := fmt.Sprintf("ReconcileCnsVolumeMetadata: Failed to update status for %q. "+
309+
original := instance.DeepCopy()
310+
if err = k8s.PatchObject(ctx, r.client, original, instance); err != nil {
311+
msg := fmt.Sprintf("ReconcileCnsVolumeMetadata: Failed to patch status for %q. "+
307312
"Err: %v. Requeueing request.", instance.Name, err)
308313
recordEvent(ctx, r, instance, v1.EventTypeWarning, msg)
309314
return reconcile.Result{RequeueAfter: timeout}, err

0 commit comments

Comments
 (0)