Skip to content

Commit e98d820

Browse files
ti-chi-botliubog2008csuzhangxc
authored
fix(volume): fix panic bug when enable ModifyVolume feature (#5058) (#5082)
Signed-off-by: ti-chi-bot <[email protected]> Co-authored-by: Bo Liu <[email protected]> Co-authored-by: csuzhangxc <[email protected]>
1 parent 460ffca commit e98d820

File tree

7 files changed

+247
-169
lines changed

7 files changed

+247
-169
lines changed

pkg/manager/volumes/phase.go

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -77,44 +77,55 @@ func (p *podVolModifier) getVolumePhase(vol *ActualVolume) VolumePhase {
7777
return VolumePhaseModified
7878
}
7979

80-
if p.waitForNextTime(vol.PVC, vol.Desired.StorageClass) {
80+
if p.waitForNextTime(vol.PVC, vol.StorageClass, vol.Desired.StorageClass) {
8181
return VolumePhasePending
8282
}
8383

8484
return VolumePhasePreparing
8585
}
8686

87-
func isVolumeExpansionSupported(sc *storagev1.StorageClass) bool {
87+
func isVolumeExpansionSupported(sc *storagev1.StorageClass) (bool, error) {
88+
if sc == nil {
89+
// always assume expansion is supported
90+
return true, fmt.Errorf("expansion cap of volume is unknown")
91+
}
8892
if sc.AllowVolumeExpansion == nil {
89-
return false
93+
return false, nil
9094
}
91-
return *sc.AllowVolumeExpansion
95+
return *sc.AllowVolumeExpansion, nil
9296
}
9397

9498
func (p *podVolModifier) validate(vol *ActualVolume) error {
9599
if vol.Desired == nil {
96100
return fmt.Errorf("can't match desired volume")
97101
}
98-
if vol.Desired.StorageClass == nil {
99-
// TODO: support default storage class
100-
return fmt.Errorf("can't change storage class to the default one")
101-
}
102-
desired := vol.Desired.Size
103-
actual := getStorageSize(vol.PVC.Spec.Resources.Requests)
102+
desired := vol.Desired.GetStorageSize()
103+
actual := vol.GetStorageSize()
104104
result := desired.Cmp(actual)
105105
switch {
106106
case result == 0:
107107
case result < 0:
108108
return fmt.Errorf("can't shrunk size from %s to %s", &actual, &desired)
109109
case result > 0:
110-
if !isVolumeExpansionSupported(vol.StorageClass) {
110+
supported, err := isVolumeExpansionSupported(vol.StorageClass)
111+
if err != nil {
112+
klog.Warningf("volume expansion of storage class %s may be not supported, but it will be tried", vol.GetStorageClassName())
113+
}
114+
if !supported {
111115
return fmt.Errorf("volume expansion is not supported by storageclass %s", vol.StorageClass.Name)
112116
}
113117
}
114-
m := p.getVolumeModifier(vol.Desired.StorageClass)
118+
119+
m := p.getVolumeModifier(vol.StorageClass, vol.Desired.StorageClass)
115120
if m == nil {
116121
return nil
117122
}
123+
124+
// if no pv permission but have sc permission: cannot change sc
125+
if isStorageClassChanged(vol.GetStorageClassName(), vol.Desired.GetStorageClassName()) && vol.PV == nil {
126+
return fmt.Errorf("cannot change storage class (%s to %s), because there is no permission to get persistent volume", vol.GetStorageClassName(), vol.Desired.GetStorageClassName())
127+
}
128+
118129
desiredPVC := vol.PVC.DeepCopy()
119130
desiredPVC.Spec.Resources.Requests[corev1.ResourceStorage] = desired
120131

@@ -128,7 +139,7 @@ func isPVCRevisionChanged(pvc *corev1.PersistentVolumeClaim) bool {
128139
return specRevision != statusRevision
129140
}
130141

131-
func (p *podVolModifier) waitForNextTime(pvc *corev1.PersistentVolumeClaim, sc *storagev1.StorageClass) bool {
142+
func (p *podVolModifier) waitForNextTime(pvc *corev1.PersistentVolumeClaim, actualSc, desciredSc *storagev1.StorageClass) bool {
132143
str, ok := pvc.Annotations[annoKeyPVCLastTransitionTimestamp]
133144
if !ok {
134145
return false
@@ -139,7 +150,7 @@ func (p *podVolModifier) waitForNextTime(pvc *corev1.PersistentVolumeClaim, sc *
139150
}
140151
d := time.Since(timestamp)
141152

142-
m := p.getVolumeModifier(sc)
153+
m := p.getVolumeModifier(actualSc, desciredSc)
143154

144155
waitDur := defaultModifyWaitingDuration
145156
if m != nil {
@@ -156,23 +167,14 @@ func (p *podVolModifier) waitForNextTime(pvc *corev1.PersistentVolumeClaim, sc *
156167

157168
func needModify(pvc *corev1.PersistentVolumeClaim, desired *DesiredVolume) bool {
158169
size := desired.Size
159-
scName := ""
160-
if desired.StorageClass != nil {
161-
scName = desired.StorageClass.Name
162-
}
170+
scName := desired.GetStorageClassName()
163171

164172
return isPVCStatusMatched(pvc, scName, size)
165173
}
166174

167175
func isPVCStatusMatched(pvc *corev1.PersistentVolumeClaim, scName string, size resource.Quantity) bool {
168-
isChanged := false
169-
oldSc, ok := pvc.Annotations[annoKeyPVCStatusStorageClass]
170-
if !ok {
171-
oldSc = ignoreNil(pvc.Spec.StorageClassName)
172-
}
173-
if oldSc != scName {
174-
isChanged = true
175-
}
176+
oldSc := getStorageClassNameFromPVC(pvc)
177+
isChanged := isStorageClassChanged(oldSc, scName)
176178

177179
oldSize, ok := pvc.Annotations[annoKeyPVCStatusStorageSize]
178180
if !ok {
@@ -188,3 +190,10 @@ func isPVCStatusMatched(pvc *corev1.PersistentVolumeClaim, scName string, size r
188190

189191
return isChanged
190192
}
193+
194+
func isStorageClassChanged(pre, cur string) bool {
195+
if cur != "" && pre != cur {
196+
return true
197+
}
198+
return false
199+
}

pkg/manager/volumes/phase_test.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ func newTestPVCForGetVolumePhase(size string, sc *string, annotations map[string
4343
},
4444
StorageClassName: sc,
4545
},
46+
Status: corev1.PersistentVolumeClaimStatus{
47+
Capacity: corev1.ResourceList{
48+
corev1.ResourceStorage: q,
49+
},
50+
},
4651
}
4752
}
4853

@@ -169,13 +174,22 @@ func TestGetVolumePhase(t *testing.T) {
169174
expected: VolumePhasePreparing,
170175
},
171176
{
172-
desc: "invalid sc",
177+
desc: "sc is not set",
173178
pvc: newTestPVCForGetVolumePhase(oldSize, &oldScName, nil),
174179
oldSc: newStorageClassForGetVolumePhase(oldScName, "ebs.csi.aws.com", true),
175180
sc: nil,
176181
size: oldSize,
177182

178-
expected: VolumePhaseCannotModify,
183+
expected: VolumePhaseModified,
184+
},
185+
{
186+
desc: "sc is not set, but size is changed",
187+
pvc: newTestPVCForGetVolumePhase(oldSize, &oldScName, nil),
188+
oldSc: newStorageClassForGetVolumePhase(oldScName, "ebs.csi.aws.com", true),
189+
sc: nil,
190+
size: newSize,
191+
192+
expected: VolumePhasePreparing,
179193
},
180194
{
181195
desc: "invalid size",
@@ -217,14 +231,22 @@ func TestGetVolumePhase(t *testing.T) {
217231
actual := ActualVolume{
218232
PVC: c.pvc,
219233
StorageClass: c.oldSc,
234+
PV: &corev1.PersistentVolume{
235+
ObjectMeta: metav1.ObjectMeta{
236+
Name: "test",
237+
},
238+
},
220239
}
221240
if !c.noDesired {
222241
actual.Desired = &DesiredVolume{
223242
StorageClass: c.sc,
224243
Size: resource.MustParse(c.size),
225244
}
245+
if c.sc != nil {
246+
actual.Desired.StorageClassName = &c.sc.Name
247+
}
226248
}
227249
phase := pvm.getVolumePhase(&actual)
228-
g.Expect(phase).Should(Equal(c.expected), c.desc)
250+
g.Expect(phase.String()).Should(Equal(c.expected.String()), c.desc)
229251
}
230252
}

0 commit comments

Comments
 (0)