diff --git a/pkg/controller/expand_and_recover.go b/pkg/controller/expand_and_recover.go index 8fcb585c9..8f3a73185 100644 --- a/pkg/controller/expand_and_recover.go +++ b/pkg/controller/expand_and_recover.go @@ -22,6 +22,7 @@ import ( "github.com/kubernetes-csi/external-resizer/pkg/util" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog/v2" ) @@ -196,6 +197,27 @@ func (ctrl *resizeController) expandAndRecover(pvc *v1.PersistentVolumeClaim, pv return pvc, pv, nil, true } +func (ctrl *resizeController) removeNodeExpansionNotRequiredAnnotation(pvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim { + if !metav1.HasAnnotation(pvc.ObjectMeta, util.NodeExpansionNotRequired) { + return pvc + } + + delete(pvc.Annotations, util.NodeExpansionNotRequired) + return pvc +} + +func (ctrl *resizeController) addNodeExpansionNotRequiredAnnotation(pvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim { + if metav1.HasAnnotation(pvc.ObjectMeta, util.NodeExpansionNotRequired) { + return pvc + } + + if pvc.Annotations == nil { + pvc.Annotations = make(map[string]string) + } + pvc.Annotations[util.NodeExpansionNotRequired] = "true" + return pvc +} + func (ctrl *resizeController) markForSlowRetry(pvcKey string, resizeStatus v1.ClaimResourceStatus) { if resizeStatus == v1.PersistentVolumeClaimControllerResizeInfeasible { ctrl.slowSet.Add(pvcKey) diff --git a/pkg/controller/expand_and_recover_test.go b/pkg/controller/expand_and_recover_test.go index 469db86c6..8d86d21e4 100644 --- a/pkg/controller/expand_and_recover_test.go +++ b/pkg/controller/expand_and_recover_test.go @@ -9,10 +9,12 @@ import ( "github.com/kubernetes-csi/external-resizer/pkg/features" "github.com/kubernetes-csi/external-resizer/pkg/resizer" "github.com/kubernetes-csi/external-resizer/pkg/testutil" + "github.com/kubernetes-csi/external-resizer/pkg/util" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -29,21 +31,24 @@ func TestExpandAndRecover(t *testing.T) { pv *v1.PersistentVolume disableNodeExpansion bool disableControllerExpansion bool + // expectations of test - expectedResizeStatus v1.ClaimResourceStatus - expectedAllocatedSize resource.Quantity - pvcWithFinalErrors sets.Set[string] - expansionError error - expectResizeCall bool - expectedConditions []v1.PersistentVolumeClaimConditionType + expectedResizeStatus v1.ClaimResourceStatus + expectedAllocatedSize resource.Quantity + expectNodeExpansionNotRequiredAnnotation bool + pvcWithFinalErrors sets.Set[string] + expansionError error + expectResizeCall bool + expectedConditions []v1.PersistentVolumeClaimConditionType }{ { - name: "pvc.spec.size > pv.spec.size, resize_status=node_expansion_inprogress", - pvc: testutil.GetTestPVC("test-vol0", "2G", "1G", "", ""), - pv: createPV(1, "claim01", defaultNS, "test-uid", &fsVolumeMode), - expectedResizeStatus: v1.PersistentVolumeClaimNodeResizePending, - expectedAllocatedSize: resource.MustParse("2G"), - expectResizeCall: true, + name: "pvc.spec.size > pv.spec.size, resize_status=node_expansion_inprogress", + pvc: testutil.GetTestPVC("test-vol0", "2G", "1G", "", ""), + pv: createPV(1, "claim01", defaultNS, "test-uid", &fsVolumeMode), + expectedResizeStatus: v1.PersistentVolumeClaimNodeResizePending, + expectNodeExpansionNotRequiredAnnotation: false, + expectedAllocatedSize: resource.MustParse("2G"), + expectResizeCall: true, }, { name: "pvc.spec.size = pv.spec.size, resize_status=no_expansion_inprogress", @@ -116,13 +121,14 @@ func TestExpandAndRecover(t *testing.T) { expectResizeCall: false, }, { - name: "pvc.spec.size > pv.spec.size, disable_node_expansion=true, resize_status=no_expansion_inprogress", - pvc: testutil.GetTestPVC("test-vol0", "2G", "1G", "", ""), - pv: createPV(1, "claim01", defaultNS, "test-uid", &fsVolumeMode), - disableNodeExpansion: true, - expectedResizeStatus: "", - expectedAllocatedSize: resource.MustParse("2G"), - expectResizeCall: true, + name: "pvc.spec.size > pv.spec.size, disable_node_expansion=true, resize_status=no_expansion_inprogress", + pvc: testutil.GetTestPVC("test-vol0", "2G", "1G", "", ""), + pv: createPV(1, "claim01", defaultNS, "test-uid", &fsVolumeMode), + disableNodeExpansion: true, + expectedResizeStatus: "", + expectNodeExpansionNotRequiredAnnotation: true, + expectedAllocatedSize: resource.MustParse("2G"), + expectResizeCall: true, }, { name: "pv.spec.size >= pvc.spec.size, resize_status=node_expansion_failed", @@ -193,6 +199,10 @@ func TestExpandAndRecover(t *testing.T) { t.Fatalf("expected resize status to be %s, got %s", test.expectedResizeStatus, actualResizeStatus) } + if test.expectNodeExpansionNotRequiredAnnotation != metav1.HasAnnotation(pvc.ObjectMeta, util.NodeExpansionNotRequired) { + t.Fatalf("expected node expansion not required annotation to be %t, got %t", test.expectNodeExpansionNotRequiredAnnotation, metav1.HasAnnotation(pvc.ObjectMeta, util.NodeExpansionNotRequired)) + } + actualAllocatedSize := pvc.Status.AllocatedResources.Storage() if test.expectedAllocatedSize.Cmp(*actualAllocatedSize) != 0 { diff --git a/pkg/controller/resize_status.go b/pkg/controller/resize_status.go index cabecb7e0..02e1c542b 100644 --- a/pkg/controller/resize_status.go +++ b/pkg/controller/resize_status.go @@ -47,6 +47,8 @@ func (ctrl *resizeController) markControllerResizeInProgress( newPVC.Status.Conditions = util.MergeResizeConditionsOfPVC(newPVC.Status.Conditions, conditions, true /*keepOldResizeConditions*/) } + newPVC = ctrl.removeNodeExpansionNotRequiredAnnotation(newPVC) + if updateStatus { newPVC = mergeStorageResourceStatus(newPVC, v1.PersistentVolumeClaimControllerResizeInProgress) } @@ -78,6 +80,9 @@ func (ctrl *resizeController) markForPendingNodeExpansion(pvc *v1.PersistentVolu newPVC.Status.Conditions = util.MergeResizeConditionsOfPVC(newPVC.Status.Conditions, []v1.PersistentVolumeClaimCondition{pvcCondition}, true /*keepOldResizeConditions*/) + // make sure if any annotation was previously added is removed here + newPVC = ctrl.removeNodeExpansionNotRequiredAnnotation(newPVC) + newPVC = mergeStorageResourceStatus(newPVC, v1.PersistentVolumeClaimNodeResizePending) updatedPVC, err := util.PatchClaim(ctrl.kubeClient, pvc, newPVC, true /* addResourceVersionCheck */) @@ -173,6 +178,9 @@ func (ctrl *resizeController) markOverallExpansionAsFinished( newPVC.Status.AllocatedResourceStatuses = resourceStatusMap } + // this will ensure that kubelet does not try to resize volume again + newPVC = ctrl.addNodeExpansionNotRequiredAnnotation(newPVC) + updatedPVC, err := util.PatchClaim(ctrl.kubeClient, pvc, newPVC, true /* addResourceVersionCheck */) if err != nil { return pvc, fmt.Errorf("mark PVC %q as resize finished failed: %v", klog.KObj(pvc), err) diff --git a/pkg/util/util.go b/pkg/util/util.go index 18b80d95f..5bb0c10ca 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -53,6 +53,8 @@ var ( // Its value will be set by the external-resizer when it deems that filesystem resize is required after resizing volume. // Its value will be used by pv_controller to determine pvc's status capacity when binding pvc and pv. AnnPreResizeCapacity = "volume.alpha.kubernetes.io/pre-resize-capacity" + + NodeExpansionNotRequired = "volume.kubernetes.io/node-expansion-not-required" ) // MergeResizeConditionsOfPVC updates pvc with requested resize conditions