Skip to content

Commit

Permalink
Replaces Update with Patch for PersistentVolumeClaims
Browse files Browse the repository at this point in the history
Signed-off-by: Grant Griffiths <ggriffiths@purestorage.com>
  • Loading branch information
Grant Griffiths committed Oct 31, 2023
1 parent 9dcaddc commit 90c40b6
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 2 deletions.
5 changes: 3 additions & 2 deletions pkg/common-controller/snapshot_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,8 @@ func (ctrl *csiSnapshotCommonController) ensurePVCFinalizer(snapshot *crdv1.Volu
// If PVC is not being deleted and PVCFinalizer is not added yet, add the PVCFinalizer.
pvcClone := pvc.DeepCopy()
pvcClone.ObjectMeta.Finalizers = append(pvcClone.ObjectMeta.Finalizers, utils.PVCFinalizer)
_, err = ctrl.client.CoreV1().PersistentVolumeClaims(pvcClone.Namespace).Update(context.TODO(), pvcClone, metav1.UpdateOptions{})

_, err = utils.PatchPersistentVolumeClaim(ctrl.client, pvc, pvcClone, true)
if err != nil {
klog.Errorf("cannot add finalizer on claim [%s/%s] for snapshot [%s/%s]: [%v]", pvc.Namespace, pvc.Name, snapshot.Namespace, snapshot.Name, err)
return newControllerUpdateError(pvcClone.Name, err.Error())
Expand All @@ -930,7 +931,7 @@ func (ctrl *csiSnapshotCommonController) removePVCFinalizer(pvc *v1.PersistentVo
pvcClone := pvc.DeepCopy()
pvcClone.ObjectMeta.Finalizers = utils.RemoveString(pvcClone.ObjectMeta.Finalizers, utils.PVCFinalizer)

_, err := ctrl.client.CoreV1().PersistentVolumeClaims(pvcClone.Namespace).Update(context.TODO(), pvcClone, metav1.UpdateOptions{})
_, err := utils.PatchPersistentVolumeClaim(ctrl.client, pvc, pvcClone, true)
if err != nil {
return newControllerUpdateError(pvcClone.Name, err.Error())
}
Expand Down
76 changes: 76 additions & 0 deletions pkg/utils/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@ package utils
import (
"context"
"encoding/json"
"fmt"

crdv1alpha1 "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumegroupsnapshot/v1alpha1"

crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumesnapshot/v1"
clientset "github.com/kubernetes-csi/external-snapshotter/client/v6/clientset/versioned"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/kubernetes"
)

// PatchOp represents a json patch operation
Expand Down Expand Up @@ -77,3 +84,72 @@ func PatchVolumeGroupSnapshotContent(

return newGroupSnapshotContent, nil
}

func PatchPersistentVolumeClaim(client kubernetes.Interface, oldPVC, newPVC *v1.PersistentVolumeClaim, addResourceVersionCheck bool) (*v1.PersistentVolumeClaim, error) {
patchBytes, err := GetPVCPatchData(oldPVC, newPVC, addResourceVersionCheck)
if err != nil {
return oldPVC, fmt.Errorf("can't patch status of PVC %s as generate path data failed: %v", PVCKey(oldPVC), err)
}
updatedClaim, updateErr := client.CoreV1().PersistentVolumeClaims(oldPVC.Namespace).
Patch(context.TODO(), oldPVC.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status")
if updateErr != nil {
return oldPVC, fmt.Errorf("can't patch status of PVC %s with %v", PVCKey(oldPVC), updateErr)
}

return updatedClaim, nil
}

// PVCKey returns an unique key of a PVC object,
func PVCKey(pvc *v1.PersistentVolumeClaim) string {
return fmt.Sprintf("%s/%s", pvc.Namespace, pvc.Name)
}

func GetPVCPatchData(oldPVC, newPVC *v1.PersistentVolumeClaim, addResourceVersionCheck bool) ([]byte, error) {
patchBytes, err := GetPatchData(oldPVC, newPVC)
if err != nil {
return patchBytes, err
}

if addResourceVersionCheck {
patchBytes, err = addResourceVersion(patchBytes, oldPVC.ResourceVersion)
if err != nil {
return nil, fmt.Errorf("apply ResourceVersion to patch data failed: %v", err)
}
}
return patchBytes, nil
}

func GetPatchData(oldObj, newObj interface{}) ([]byte, error) {
oldData, err := json.Marshal(oldObj)
if err != nil {
return nil, fmt.Errorf("marshal old object failed: %v", err)
}
newData, err := json.Marshal(newObj)
if err != nil {
return nil, fmt.Errorf("marshal new object failed: %v", err)
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, oldObj)
if err != nil {
return nil, fmt.Errorf("CreateTwoWayMergePatch failed: %v", err)
}
return patchBytes, nil
}

func addResourceVersion(patchBytes []byte, resourceVersion string) ([]byte, error) {
var patchMap map[string]interface{}
err := json.Unmarshal(patchBytes, &patchMap)
if err != nil {
return nil, fmt.Errorf("error unmarshalling patch with %v", err)
}
u := unstructured.Unstructured{Object: patchMap}
a, err := meta.Accessor(&u)
if err != nil {
return nil, fmt.Errorf("error creating accessor with %v", err)
}
a.SetResourceVersion(resourceVersion)
versionBytes, err := json.Marshal(patchMap)
if err != nil {
return nil, fmt.Errorf("error marshalling json patch with %v", err)
}
return versionBytes, nil
}

0 comments on commit 90c40b6

Please sign in to comment.