Skip to content

Enable Rollback Support of VAC with Infeasible Errors #487

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions pkg/modifycontroller/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"context"
"errors"
"fmt"
"testing"
"time"

"github.com/kubernetes-csi/external-resizer/pkg/util"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/cache"
"testing"
"time"

"github.com/kubernetes-csi/external-resizer/pkg/features"

Expand All @@ -27,7 +28,7 @@ import (
)

func TestController(t *testing.T) {
basePVC := createTestPVC(pvcName, testVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/)
basePVC := createTestPVC(pvcName, testVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/)
basePV := createTestPV(1, pvcName, pvcNamespace, "foobaz" /*pvcUID*/, &fsVolumeMode, testVac)
firstTimePV := basePV.DeepCopy()
firstTimePV.Spec.VolumeAttributesClassName = nil
Expand All @@ -44,7 +45,7 @@ func TestController(t *testing.T) {
}{
{
name: "Modify called",
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/),
pv: basePV,
vacExists: true,
callCSIModify: true,
Expand Down Expand Up @@ -104,14 +105,14 @@ func TestModifyPVC(t *testing.T) {
}{
{
name: "Modify succeeded",
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/),
pv: basePV,
modifyFailure: false,
expectFailure: false,
},
{
name: "Modify failed",
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/),
pv: basePV,
modifyFailure: true,
expectFailure: true,
Expand Down Expand Up @@ -145,16 +146,16 @@ func TestModifyPVC(t *testing.T) {
}

func TestSyncPVC(t *testing.T) {
basePVC := createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/)
basePVC := createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/)
basePV := createTestPV(1, pvcName, pvcNamespace, "foobaz" /*pvcUID*/, &fsVolumeMode, testVac)

otherDriverPV := createTestPV(1, pvcName, pvcNamespace, "foobaz" /*pvcUID*/, &fsVolumeMode, testVac)
otherDriverPV.Spec.PersistentVolumeSource.CSI.Driver = "some-other-driver"

unboundPVC := createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/)
unboundPVC := createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/)
unboundPVC.Status.Phase = v1.ClaimPending

pvcWithUncreatedPV := createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/)
pvcWithUncreatedPV := createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/)
pvcWithUncreatedPV.Spec.VolumeName = ""

nonCSIPVC := &v1.PersistentVolumeClaim{
Expand Down Expand Up @@ -196,7 +197,7 @@ func TestSyncPVC(t *testing.T) {
},
{
name: "Should NOT modify if PVC has empty Spec.VACName",
pvc: createTestPVC(pvcName, "" /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, "" /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/),
pv: basePV,
callCSIModify: false,
},
Expand Down Expand Up @@ -247,7 +248,7 @@ func TestSyncPVC(t *testing.T) {

// TestInfeasibleRetry tests that sidecar doesn't spam plugin upon infeasible error code (e.g. invalid VAC parameter)
func TestInfeasibleRetry(t *testing.T) {
basePVC := createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/)
basePVC := createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/)
basePV := createTestPV(1, pvcName, pvcNamespace, "foobaz" /*pvcUID*/, &fsVolumeMode, testVac)

tests := []struct {
Expand Down
18 changes: 18 additions & 0 deletions pkg/modifycontroller/modify_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,24 @@ func (ctrl *modifyController) modify(pvc *v1.PersistentVolumeClaim, pv *v1.Persi
}
return ctrl.controllerModifyVolumeWithTarget(pvc, pv, vac, pvcSpecVacName)
}
} else if pvcSpecVacName != nil && curVacName != nil && pvc.Status.ModifyVolumeStatus != nil && *pvcSpecVacName == *curVacName {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can pvcSpecVacName ever be nil in this code path? I think that, this code is way harder to read and understand because all the used if and else conditions need to be simplified.

targetVacName := pvc.Status.ModifyVolumeStatus.TargetVolumeAttributesClassName
// Allow rollback of VAC if it is in infeasible state
if targetVacName != "" && targetVacName != *curVacName && pvc.Status.ModifyVolumeStatus.Status == v1.PersistentVolumeClaimModifyVolumeInfeasible {
vac, err := ctrl.vacLister.Get(*pvcSpecVacName)
if err != nil {
return pvc, pv, err, false
}
// Mark pvc.Status.ModifyVolumeStatus as in progress
pvc, err = ctrl.markControllerModifyVolumeStatus(pvc, v1.PersistentVolumeClaimModifyVolumeInProgress, nil)
if err != nil {
return pvc, pv, err, false
}
// Record an event to indicate that external resizer is rolling back VAC in this volume.
ctrl.eventRecorder.Event(pvc, v1.EventTypeNormal, util.VolumeModify,
fmt.Sprintf("external resizer is rolling back a modification of the volume %s to vac %s", pvc.Name, *pvcSpecVacName))
return ctrl.controllerModifyVolumeWithTarget(pvc, pv, vac, pvcSpecVacName)
}
}

// No modification required
Expand Down
22 changes: 16 additions & 6 deletions pkg/modifycontroller/modify_volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var (
)

func TestModify(t *testing.T) {
basePVC := createTestPVC(pvcName, testVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/)
basePVC := createTestPVC(pvcName, testVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/)
basePV := createTestPV(1, pvcName, pvcNamespace, "foobaz" /*pvcUID*/, &fsVolumeMode, testVac)

var tests = []struct {
Expand All @@ -61,7 +61,7 @@ func TestModify(t *testing.T) {
},
{
name: "vac does not exist, no modification and set ModifyVolumeStatus to pending",
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/),
pv: basePV,
expectModifyCall: false,
expectedModifyVolumeStatus: &v1.ModifyVolumeStatus{
Expand All @@ -73,7 +73,7 @@ func TestModify(t *testing.T) {
},
{
name: "modify volume success",
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/),
pv: basePV,
vacExists: true,
expectModifyCall: true,
Expand All @@ -83,7 +83,7 @@ func TestModify(t *testing.T) {
},
{
name: "modify volume success with extra metadata",
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/),
pvc: createTestPVC(pvcName, targetVac /*vacName*/, testVac /*curVacName*/, testVac /*targetVacName*/, "" /*modifyVolumeStatus*/),
pv: basePV,
vacExists: true,
expectModifyCall: true,
Expand All @@ -98,6 +98,16 @@ func TestModify(t *testing.T) {
"csi.storage.k8s.io/pv/name": "testPV",
},
},
{
name: "modify volume rollback succeeds for infeasible errors",
pvc: createTestPVC(pvcName, testVac /*vacName*/, targetVac /*curVacName*/, testVac /*targetVacName*/, v1.PersistentVolumeClaimModifyVolumeInfeasible),
pv: basePV,
vacExists: true,
expectModifyCall: true,
expectedModifyVolumeStatus: nil,
expectedCurrentVolumeAttributesClassName: &testVac,
expectedPVVolumeAttributesClassName: &testVac,
},
}

for i := range tests {
Expand Down Expand Up @@ -154,7 +164,7 @@ func TestModify(t *testing.T) {
}
}

func createTestPVC(pvcName string, vacName string, curVacName string, targetVacName string) *v1.PersistentVolumeClaim {
func createTestPVC(pvcName string, vacName string, curVacName string, targetVacName string, modifyVolumeStatus v1.PersistentVolumeClaimModifyVolumeStatus) *v1.PersistentVolumeClaim {
pvc := &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: pvcName, Namespace: pvcNamespace},
Spec: v1.PersistentVolumeClaimSpec{
Expand All @@ -178,7 +188,7 @@ func createTestPVC(pvcName string, vacName string, curVacName string, targetVacN
CurrentVolumeAttributesClassName: &curVacName,
ModifyVolumeStatus: &v1.ModifyVolumeStatus{
TargetVolumeAttributesClassName: targetVacName,
Status: "",
Status: modifyVolumeStatus,
},
},
}
Expand Down