Skip to content

Commit 55abf9f

Browse files
committed
Use Patch operation for PV & PVC updates
1 parent 7a6acd9 commit 55abf9f

File tree

12 files changed

+519
-59
lines changed

12 files changed

+519
-59
lines changed

pkg/csi/service/common/commonco/k8sorchestrator/k8sorchestrator.go

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package k8sorchestrator
1919
import (
2020
"context"
2121
"crypto/sha256"
22+
"encoding/json"
2223
"errors"
2324
"fmt"
2425
"os"
@@ -44,6 +45,7 @@ import (
4445
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
4546
"k8s.io/apimachinery/pkg/runtime"
4647
k8stypes "k8s.io/apimachinery/pkg/types"
48+
"k8s.io/apimachinery/pkg/util/strategicpatch"
4749
"k8s.io/client-go/informers"
4850
clientset "k8s.io/client-go/kubernetes"
4951
restclient "k8s.io/client-go/rest"
@@ -2173,15 +2175,36 @@ func (c *K8sOrchestrator) PreLinkedCloneCreateAction(ctx context.Context, pvcNam
21732175
return err
21742176
}
21752177

2176-
if linkedClonePVC.Labels == nil {
2177-
linkedClonePVC.Labels = make(map[string]string)
2178+
oldData, err := json.Marshal(linkedClonePVC)
2179+
if err != nil {
2180+
log.Errorf("Failed to marshal PVC %s/%s: %v", pvcNamespace, pvcName, err)
2181+
return err
2182+
}
2183+
2184+
newPVC := linkedClonePVC.DeepCopy()
2185+
if newPVC.Labels == nil {
2186+
newPVC.Labels = make(map[string]string)
21782187
}
21792188
// Add label
2180-
if _, ok := linkedClonePVC.Labels[common.AnnKeyLinkedClone]; !ok {
2181-
linkedClonePVC.Labels[common.LinkedClonePVCLabel] = linkedClonePVC.Annotations[common.AttributeIsLinkedClone]
2189+
if _, ok := newPVC.Labels[common.AnnKeyLinkedClone]; !ok {
2190+
newPVC.Labels[common.LinkedClonePVCLabel] = newPVC.Annotations[common.AttributeIsLinkedClone]
2191+
}
2192+
2193+
newData, err := json.Marshal(newPVC)
2194+
if err != nil {
2195+
log.Errorf("Failed to marshal updated PVC %s/%s with labels: %v", pvcNamespace, pvcName, err)
2196+
return err
21822197
}
21832198

2184-
_, err = c.k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Update(ctx, linkedClonePVC, metav1.UpdateOptions{})
2199+
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, linkedClonePVC)
2200+
if err != nil {
2201+
log.Errorf("Error creating two way merge patch for PVC %s/%s with error: %v", pvcNamespace, pvcName, err)
2202+
return err
2203+
}
2204+
2205+
_, err = c.k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Patch(ctx, linkedClonePVC.Name,
2206+
k8stypes.StrategicMergePatchType,
2207+
patchBytes, metav1.PatchOptions{})
21852208
if err != nil {
21862209
log.Errorf("failed to add linked clone label for PVC %s/%s. Error: %+v, retrying...",
21872210
pvcNamespace, pvcName, err)
@@ -2229,11 +2252,36 @@ func (c *K8sOrchestrator) UpdatePersistentVolumeLabel(ctx context.Context,
22292252
if err != nil {
22302253
return fmt.Errorf("error getting PV %s from API server: %w", pvName, err)
22312254
}
2232-
if pv.Labels == nil {
2233-
pv.Labels = make(map[string]string)
2255+
2256+
oldData, err := json.Marshal(pv)
2257+
if err != nil {
2258+
errMsg := fmt.Sprintf("Failed to marshal PV %s: %v", pvName, err)
2259+
log.Error(errMsg)
2260+
return err
2261+
}
2262+
2263+
newPV := pv.DeepCopy()
2264+
if newPV.Labels == nil {
2265+
newPV.Labels = make(map[string]string)
2266+
}
2267+
newPV.Labels[key] = value
2268+
2269+
newData, err := json.Marshal(newPV)
2270+
if err != nil {
2271+
errMsg := fmt.Sprintf("Failed to marshal updated PV %s with labels: %v", pvName, err)
2272+
log.Error(errMsg)
2273+
return err
22342274
}
2235-
pv.Labels[key] = value
2236-
_, err = c.k8sClient.CoreV1().PersistentVolumes().Update(ctx, pv, metav1.UpdateOptions{})
2275+
2276+
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, pv)
2277+
if err != nil {
2278+
errMsg := fmt.Sprintf("Error creating two way merge patch for PV %s with error: %v", pvName, err)
2279+
log.Error(errMsg)
2280+
return err
2281+
}
2282+
2283+
_, err = c.k8sClient.CoreV1().PersistentVolumes().Patch(ctx, pv.Name, k8stypes.StrategicMergePatchType,
2284+
patchBytes, metav1.PatchOptions{})
22372285
if err != nil {
22382286
errMsg := fmt.Sprintf("error updating PV %s with labels %s/%s. Error: %v", pvName, key, value, err)
22392287
log.Error(errMsg)

pkg/csi/service/common/commonco/k8sorchestrator/k8sorchestrator_helper.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"time"
2424

2525
k8stypes "k8s.io/apimachinery/pkg/types"
26+
"k8s.io/apimachinery/pkg/util/strategicpatch"
2627
"k8s.io/apimachinery/pkg/util/wait"
2728

2829
v1 "k8s.io/api/core/v1"
@@ -83,17 +84,38 @@ func (c *K8sOrchestrator) updatePVCAnnotations(ctx context.Context,
8384
return err
8485
}
8586

87+
oldData, err := json.Marshal(pvcObj)
88+
if err != nil {
89+
log.Errorf("failed to marshal PVC %s/%s: %v", pvcNamespace, pvcName, err)
90+
return err
91+
}
92+
93+
newPVC := pvcObj.DeepCopy()
8694
for key, val := range annotations {
8795
// If value is not set, remove the annotation.
8896
if val == "" {
89-
delete(pvcObj.ObjectMeta.Annotations, key)
97+
delete(newPVC.ObjectMeta.Annotations, key)
9098
log.Debugf("Removing annotation %s on pvc %s/%s", key, pvcNamespace, pvcName)
9199
} else {
92-
metav1.SetMetaDataAnnotation(&pvcObj.ObjectMeta, key, val)
100+
metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, key, val)
93101
log.Debugf("Updating annotation %s on pvc %s/%s to value: %s", key, pvcNamespace, pvcName, val)
94102
}
95103
}
96-
_, err = c.k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Update(ctx, pvcObj, metav1.UpdateOptions{})
104+
105+
newData, err := json.Marshal(newPVC)
106+
if err != nil {
107+
log.Errorf("failed to marshal updated PVC %s/%s with annotations: %v", pvcNamespace, pvcName, err)
108+
return err
109+
}
110+
111+
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, pvcObj)
112+
if err != nil {
113+
log.Errorf("error creating two way merge patch for PVC %s/%s: %v", pvcNamespace, pvcName, err)
114+
return err
115+
}
116+
117+
_, err = c.k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Patch(ctx, pvcObj.Name,
118+
k8stypes.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
97119
if err != nil {
98120
log.Errorf("failed to update pvc annotations %s/%s with err:%+v", pvcNamespace, pvcName, err)
99121
return err

pkg/csi/service/wcpguest/controller.go

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package wcpguest
1818

1919
import (
2020
"context"
21+
"encoding/json"
2122
"fmt"
2223
"math"
2324
"net/http"
@@ -48,6 +49,7 @@ import (
4849
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4950
"k8s.io/apimachinery/pkg/fields"
5051
"k8s.io/apimachinery/pkg/types"
52+
"k8s.io/apimachinery/pkg/util/strategicpatch"
5153
"k8s.io/apimachinery/pkg/watch"
5254
clientset "k8s.io/client-go/kubernetes"
5355
"k8s.io/client-go/rest"
@@ -622,10 +624,37 @@ func (c *controller) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequ
622624
if finalizer == cnsoperatortypes.CNSVolumeFinalizer {
623625
log.Infof("Removing %q finalizer from PersistentVolumeClaim with name: %q on namespace: %q",
624626
cnsoperatortypes.CNSVolumeFinalizer, svPVC.Name, svPVC.Namespace)
625-
svPVC.ObjectMeta.Finalizers = slices.Delete(svPVC.ObjectMeta.Finalizers, i, i+1)
627+
628+
oldData, err := json.Marshal(svPVC)
629+
if err != nil {
630+
msg := fmt.Sprintf("failed to marshal supervisor PVC %q in %q namespace. Error: %+v",
631+
req.VolumeId, c.supervisorNamespace, err)
632+
log.Error(msg)
633+
return nil, csifault.CSIInternalFault, status.Error(codes.Internal, msg)
634+
}
635+
636+
newPVC := svPVC.DeepCopy()
637+
newPVC.ObjectMeta.Finalizers = slices.Delete(newPVC.ObjectMeta.Finalizers, i, i+1)
638+
639+
newData, err := json.Marshal(newPVC)
640+
if err != nil {
641+
msg := fmt.Sprintf("failed to marshal updated supervisor PVC %q in %q namespace. Error: %+v",
642+
req.VolumeId, c.supervisorNamespace, err)
643+
log.Error(msg)
644+
return nil, csifault.CSIInternalFault, status.Error(codes.Internal, msg)
645+
}
646+
647+
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, svPVC)
648+
if err != nil {
649+
msg := fmt.Sprintf("error creating two way merge patch for supervisor PVC %q in %q namespace. Error: %+v",
650+
req.VolumeId, c.supervisorNamespace, err)
651+
log.Error(msg)
652+
return nil, csifault.CSIInternalFault, status.Error(codes.Internal, msg)
653+
}
654+
626655
// Update the instance after removing finalizer
627-
_, err := c.supervisorClient.CoreV1().PersistentVolumeClaims(c.supervisorNamespace).Update(ctx, svPVC,
628-
metav1.UpdateOptions{})
656+
_, err = c.supervisorClient.CoreV1().PersistentVolumeClaims(c.supervisorNamespace).Patch(ctx,
657+
svPVC.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{})
629658
if err != nil {
630659
msg := fmt.Sprintf("failed to update supervisor PVC %q in %q namespace. Error: %+v",
631660
req.VolumeId, c.supervisorNamespace, err)
@@ -1466,14 +1495,38 @@ func (c *controller) ControllerExpandVolume(ctx context.Context, req *csi.Contro
14661495
switch (gcPvcRequestSize).Cmp(svPvcRequestSize) {
14671496
case 1:
14681497
// Update requested storage in SV PVC spec
1469-
svPvcClone := svPVC.DeepCopy()
1470-
svPvcClone.Spec.Resources.Requests[corev1.ResourceName(corev1.ResourceStorage)] = *gcPvcRequestSize
1498+
oldExpandData, err := json.Marshal(svPVC)
1499+
if err != nil {
1500+
msg := fmt.Sprintf("failed to marshal supervisor PVC for expansion %q in %q namespace. Error: %+v",
1501+
volumeID, c.supervisorNamespace, err)
1502+
log.Error(msg)
1503+
return nil, csifault.CSIInternalFault, status.Error(codes.Internal, msg)
1504+
}
1505+
1506+
newExpandPVC := svPVC.DeepCopy()
1507+
newExpandPVC.Spec.Resources.Requests[corev1.ResourceName(corev1.ResourceStorage)] = *gcPvcRequestSize
1508+
1509+
newExpandData, err := json.Marshal(newExpandPVC)
1510+
if err != nil {
1511+
msg := fmt.Sprintf("failed to marshal updated supervisor PVC for expansion %q in %q namespace. Error: %+v",
1512+
volumeID, c.supervisorNamespace, err)
1513+
log.Error(msg)
1514+
return nil, csifault.CSIInternalFault, status.Error(codes.Internal, msg)
1515+
}
1516+
1517+
expandPatchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldExpandData, newExpandData, svPVC)
1518+
if err != nil {
1519+
msg := fmt.Sprintf("error creating two way merge patch for supervisor PVC expansion %q in %q namespace. Error: %+v",
1520+
volumeID, c.supervisorNamespace, err)
1521+
log.Error(msg)
1522+
return nil, csifault.CSIInternalFault, status.Error(codes.Internal, msg)
1523+
}
14711524

14721525
// Make an update call to SV API server
14731526
log.Infof("Increasing the size of supervisor PVC %s in namespace %s to %s",
14741527
volumeID, c.supervisorNamespace, gcPvcRequestSize.String())
1475-
svPVC, err = c.supervisorClient.CoreV1().PersistentVolumeClaims(c.supervisorNamespace).Update(
1476-
ctx, svPvcClone, metav1.UpdateOptions{})
1528+
svPVC, err = c.supervisorClient.CoreV1().PersistentVolumeClaims(c.supervisorNamespace).Patch(
1529+
ctx, svPVC.Name, types.StrategicMergePatchType, expandPatchBytes, metav1.PatchOptions{})
14771530
if err != nil {
14781531
msg := fmt.Sprintf("failed to update supervisor PVC %q in %q namespace. Error: %+v",
14791532
volumeID, c.supervisorNamespace, err)

pkg/kubernetes/kubernetes.go

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package kubernetes
1919
import (
2020
"context"
2121
"embed"
22+
"encoding/json"
2223
"flag"
2324
"fmt"
2425
"net"
@@ -40,6 +41,8 @@ import (
4041
"k8s.io/apimachinery/pkg/runtime"
4142
"k8s.io/apimachinery/pkg/runtime/schema"
4243
"k8s.io/apimachinery/pkg/runtime/serializer"
44+
k8stypes "k8s.io/apimachinery/pkg/types"
45+
"k8s.io/apimachinery/pkg/util/strategicpatch"
4346
"k8s.io/apimachinery/pkg/util/wait"
4447
utilyaml "k8s.io/apimachinery/pkg/util/yaml"
4548
clientset "k8s.io/client-go/kubernetes"
@@ -728,8 +731,28 @@ func RetainPersistentVolume(ctx context.Context, k8sClient clientset.Interface,
728731
return err
729732
}
730733

731-
pv.Spec.PersistentVolumeReclaimPolicy = v1.PersistentVolumeReclaimRetain
732-
_, err = k8sClient.CoreV1().PersistentVolumes().Update(ctx, pv, metav1.UpdateOptions{})
734+
oldData, err := json.Marshal(pv)
735+
if err != nil {
736+
log.Errorf("Failed to marshal PV: %v, Error: %v", pv, err)
737+
return err
738+
}
739+
740+
newPV := pv.DeepCopy()
741+
newPV.Spec.PersistentVolumeReclaimPolicy = v1.PersistentVolumeReclaimRetain
742+
newData, err := json.Marshal(newPV)
743+
if err != nil {
744+
log.Errorf("Failed to marshal updated PV with reclaim policy: %v, Error: %v", newPV, err)
745+
return err
746+
}
747+
748+
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, pv)
749+
if err != nil {
750+
log.Errorf("Error creating two way merge patch for PV %q with error: %v", pv.Name, err)
751+
return err
752+
}
753+
754+
_, err = k8sClient.CoreV1().PersistentVolumes().Patch(ctx, pv.Name, k8stypes.StrategicMergePatchType,
755+
patchBytes, metav1.PatchOptions{})
733756
if err != nil {
734757
log.Errorf("Failed to set the reclaim policy to retain. Error: %s", err.Error())
735758
return err
@@ -809,14 +832,34 @@ func AddFinalizerOnPVC(ctx context.Context, k8sClient clientset.Interface, pvcNa
809832
return err
810833
}
811834

835+
oldData, err := json.Marshal(pvc)
836+
if err != nil {
837+
log.Errorf("Failed to marshal PVC: %v", err)
838+
return err
839+
}
840+
841+
newPVC := pvc.DeepCopy()
812842
// If the finalizer is already present, no action is needed
813-
if !controllerutil.AddFinalizer(pvc, finalizer) {
843+
if !controllerutil.AddFinalizer(newPVC, finalizer) {
814844
log.Info("Finalizer already present on PVC. No action needed.")
815845
return nil
816846
}
817847

848+
newData, err := json.Marshal(newPVC)
849+
if err != nil {
850+
log.Errorf("Failed to marshal updated PVC with finalizer: %v", err)
851+
return err
852+
}
853+
854+
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, pvc)
855+
if err != nil {
856+
log.Errorf("Error creating two way merge patch for PVC %s/%s with error: %v", pvcNamespace, pvcName, err)
857+
return err
858+
}
859+
818860
// Update the PVC with the new finalizer
819-
_, err = k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Update(ctx, pvc, metav1.UpdateOptions{})
861+
_, err = k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Patch(ctx, pvc.Name, k8stypes.StrategicMergePatchType,
862+
patchBytes, metav1.PatchOptions{})
820863
if err != nil {
821864
log.Errorf("Failed to add finalizer on PVC. Error: %s", err.Error())
822865
return err
@@ -843,14 +886,34 @@ func RemoveFinalizerFromPVC(ctx context.Context, k8sClient clientset.Interface,
843886
return err
844887
}
845888

889+
oldData, err := json.Marshal(pvc)
890+
if err != nil {
891+
log.Errorf("Failed to marshal PVC: %v", err)
892+
return err
893+
}
894+
895+
newPVC := pvc.DeepCopy()
846896
// If the finalizer is not present, no action is needed
847-
if !controllerutil.RemoveFinalizer(pvc, finalizer) {
897+
if !controllerutil.RemoveFinalizer(newPVC, finalizer) {
848898
log.Info("Finalizer not present on PVC. No action needed.")
849899
return nil
850900
}
851901

902+
newData, err := json.Marshal(newPVC)
903+
if err != nil {
904+
log.Errorf("Failed to marshal updated PVC with finalizer removed: %v", err)
905+
return err
906+
}
907+
908+
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, pvc)
909+
if err != nil {
910+
log.Errorf("Error creating two way merge patch for PVC %s/%s with error: %v", pvcNamespace, pvcName, err)
911+
return err
912+
}
913+
852914
// Update the PVC to remove the finalizer
853-
_, err = k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Update(ctx, pvc, metav1.UpdateOptions{})
915+
_, err = k8sClient.CoreV1().PersistentVolumeClaims(pvcNamespace).Patch(ctx, pvc.Name, k8stypes.StrategicMergePatchType,
916+
patchBytes, metav1.PatchOptions{})
854917
if err != nil {
855918
log.Errorf("Failed to remove finalizer from PVC. Error: %s", err.Error())
856919
return err

0 commit comments

Comments
 (0)