@@ -30,6 +30,7 @@ import (
30
30
apierrors "k8s.io/apimachinery/pkg/api/errors"
31
31
"k8s.io/client-go/tools/cache"
32
32
"k8s.io/klog/v2"
33
+ "k8s.io/utils/ptr"
33
34
)
34
35
35
36
const (
@@ -40,8 +41,6 @@ const (
40
41
41
42
// The return value bool is only used as a sentinel value when function returns without actually performing modification
42
43
func (ctrl * modifyController ) modify (pvc * v1.PersistentVolumeClaim , pv * v1.PersistentVolume ) (* v1.PersistentVolumeClaim , * v1.PersistentVolume , error , bool ) {
43
- pvcSpecVacName := pvc .Spec .VolumeAttributesClassName
44
- curVacName := pvc .Status .CurrentVolumeAttributesClassName
45
44
pvcKey , err := cache .MetaNamespaceKeyFunc (pvc )
46
45
if err != nil {
47
46
return pvc , pv , err , false
@@ -53,60 +52,77 @@ func (ctrl *modifyController) modify(pvc *v1.PersistentVolumeClaim, pv *v1.Persi
53
52
return pvc , pv , delayModificationErr , false
54
53
}
55
54
56
- if pvcSpecVacName != nil && curVacName == nil {
57
- // First time adding VAC to a PVC
58
- return ctrl .validateVACAndModifyVolumeWithTarget (pvc , pv )
59
- } else if pvcSpecVacName != nil && curVacName != nil && * pvcSpecVacName != * curVacName {
60
- // Check if PVC in uncertain state
61
- _ , inUncertainState := ctrl .uncertainPVCs .Load (pvcKey )
62
- status := pvc .Status .ModifyVolumeStatus
63
- if ! inUncertainState || status == nil {
64
- klog .V (3 ).InfoS ("previous operation on the PVC succeeded or failed with a final error, retrying" )
65
- return ctrl .validateVACAndModifyVolumeWithTarget (pvc , pv )
66
- } else {
67
- vac , err := ctrl .vacLister .Get (status .TargetVolumeAttributesClassName )
68
- if err != nil {
69
- if apierrors .IsNotFound (err ) {
70
- ctrl .eventRecorder .Eventf (pvc , v1 .EventTypeWarning , util .VolumeModifyFailed , "VAC " + status .TargetVolumeAttributesClassName + " does not exist." )
71
- }
72
- return pvc , pv , err , false
73
- }
74
- return ctrl .controllerModifyVolumeWithTarget (pvc , pv , vac , pvcSpecVacName )
55
+ pvcSpecVacName := ptr .Deref (pvc .Spec .VolumeAttributesClassName , "" )
56
+ curVacName := ptr .Deref (pvc .Status .CurrentVolumeAttributesClassName , "" )
57
+ status := pvc .Status .ModifyVolumeStatus
58
+
59
+ if status == nil && pvcSpecVacName == curVacName {
60
+ // No modification required, already reached target state
61
+ return pvc , pv , nil , false
62
+ }
63
+
64
+ if pvcSpecVacName == "" &&
65
+ (status == nil || status .Status != v1 .PersistentVolumeClaimModifyVolumeInProgress ) {
66
+ // User don't care the target state, and we've reached a relatively stable state. Just keep it here.
67
+ // Note: APIServer generally not allowing setting pvcSpecVacName to empty when curVacName is not empty.
68
+ klog .V (4 ).InfoS ("stop reconcile for rolled back PVC" , "PV" , klog .KObj (pv ))
69
+ // Don't try to revert anything here, because we only record the result of the last modification.
70
+ // We don't know what happened before. User can switch between InProgress/Infeasible/Pending status
71
+ // freely by modifying the spec.
72
+ return pvc , pv , nil , false
73
+ }
74
+
75
+ // Check if we should change our target
76
+ _ , inUncertainState := ctrl .uncertainPVCs .Load (pvcKey )
77
+ if (status != nil && status .Status == v1 .PersistentVolumeClaimModifyVolumeInProgress && inUncertainState ) || pvcSpecVacName == "" {
78
+ vac , err := ctrl .getTargetVAC (pvc , status .TargetVolumeAttributesClassName )
79
+ if err != nil {
80
+ return pvc , pv , err , false
75
81
}
82
+ return ctrl .controllerModifyVolumeWithTarget (pvc , pv , vac )
76
83
}
77
84
78
- // No modification required
79
- return pvc , pv , nil , false
85
+ // If status != InProgress && inUncertainState, we either see a stall PVC, or the status was updated externally.
86
+ // For stall PVC, we will get Conflict when marking InProgress.
87
+ // For status updated externally, we respect the user choice and try the new target, as if it were not uncertain.
88
+ // The in-memory uncertain state will be updated after the next ControllerModifyVolume call.
89
+ return ctrl .validateVACAndModifyVolumeWithTarget (pvc , pv )
90
+ }
91
+
92
+ func (ctrl * modifyController ) getTargetVAC (pvc * v1.PersistentVolumeClaim , vacName string ) (* storagev1beta1.VolumeAttributesClass , error ) {
93
+ vac , err := ctrl .vacLister .Get (vacName )
94
+ // Check if pvcSpecVac is valid and exist
95
+ if err != nil {
96
+ if apierrors .IsNotFound (err ) {
97
+ ctrl .eventRecorder .Eventf (pvc , v1 .EventTypeWarning , util .VolumeModifyFailed , "VAC %q does not exist." , vacName )
98
+ }
99
+ return nil , fmt .Errorf ("get VAC with vac name %s in VACInformer cache failed: %w" , vacName , err )
100
+ }
101
+ return vac , nil
80
102
}
81
103
82
104
// func validateVACAndModifyVolumeWithTarget validate the VAC. The function sets pvc.Status.ModifyVolumeStatus
83
105
// to Pending if VAC does not exist and proceeds to trigger ModifyVolume if VAC exists
84
106
func (ctrl * modifyController ) validateVACAndModifyVolumeWithTarget (
85
107
pvc * v1.PersistentVolumeClaim ,
86
108
pv * v1.PersistentVolume ) (* v1.PersistentVolumeClaim , * v1.PersistentVolume , error , bool ) {
87
- // The controller only triggers ModifyVolume if pvcSpecVacName is not nil nor empty
88
- pvcSpecVacName := pvc .Spec .VolumeAttributesClassName
89
- // Check if pvcSpecVac is valid and exist
90
- vac , err := ctrl .vacLister .Get (* pvcSpecVacName )
91
- if err == nil {
92
- // Mark pvc.Status.ModifyVolumeStatus as in progress
93
- pvc , err = ctrl .markControllerModifyVolumeStatus (pvc , v1 .PersistentVolumeClaimModifyVolumeInProgress , nil )
94
- if err != nil {
95
- return pvc , pv , err , false
96
- }
97
- // Record an event to indicate that external resizer is modifying this volume.
98
- ctrl .eventRecorder .Event (pvc , v1 .EventTypeNormal , util .VolumeModify ,
99
- fmt .Sprintf ("external resizer is modifying volume %s with vac %s" , pvc .Name , * pvcSpecVacName ))
100
- return ctrl .controllerModifyVolumeWithTarget (pvc , pv , vac , pvcSpecVacName )
101
- } else {
102
- if apierrors .IsNotFound (err ) {
103
- ctrl .eventRecorder .Eventf (pvc , v1 .EventTypeWarning , util .VolumeModifyFailed , "VAC " + * pvcSpecVacName + " does not exist." )
104
- }
105
- klog .Errorf ("Get VAC with vac name %s in VACInformer cache failed: %v" , * pvcSpecVacName , err )
109
+
110
+ vac , err := ctrl .getTargetVAC (pvc , * pvc .Spec .VolumeAttributesClassName )
111
+ if err != nil {
106
112
// Mark pvc.Status.ModifyVolumeStatus as pending
107
113
pvc , err = ctrl .markControllerModifyVolumeStatus (pvc , v1 .PersistentVolumeClaimModifyVolumePending , nil )
108
114
return pvc , pv , err , false
109
115
}
116
+
117
+ // Mark pvc.Status.ModifyVolumeStatus as in progress
118
+ pvc , err = ctrl .markControllerModifyVolumeStatus (pvc , v1 .PersistentVolumeClaimModifyVolumeInProgress , nil )
119
+ if err != nil {
120
+ return pvc , pv , err , false
121
+ }
122
+ // Record an event to indicate that external resizer is modifying this volume.
123
+ ctrl .eventRecorder .Event (pvc , v1 .EventTypeNormal , util .VolumeModify ,
124
+ fmt .Sprintf ("external resizer is modifying volume %s with vac %s" , pvc .Name , vac .Name ))
125
+ return ctrl .controllerModifyVolumeWithTarget (pvc , pv , vac )
110
126
}
111
127
112
128
// func controllerModifyVolumeWithTarget trigger the CSI ControllerModifyVolume API call
@@ -115,11 +131,11 @@ func (ctrl *modifyController) controllerModifyVolumeWithTarget(
115
131
pvc * v1.PersistentVolumeClaim ,
116
132
pv * v1.PersistentVolume ,
117
133
vacObj * storagev1beta1.VolumeAttributesClass ,
118
- pvcSpecVacName * string ) (* v1.PersistentVolumeClaim , * v1.PersistentVolume , error , bool ) {
134
+ ) (* v1.PersistentVolumeClaim , * v1.PersistentVolume , error , bool ) {
119
135
var err error
120
136
pvc , pv , err = ctrl .callModifyVolumeOnPlugin (pvc , pv , vacObj )
121
137
if err == nil {
122
- klog .V (4 ).Infof ("Update volumeAttributesClass of PV %q to %s succeeded" , pv .Name , * pvcSpecVacName )
138
+ klog .V (4 ).Infof ("Update volumeAttributesClass of PV %q to %s succeeded" , pv .Name , vacObj . Name )
123
139
// Record an event to indicate that modify operation is successful.
124
140
ctrl .eventRecorder .Eventf (pvc , v1 .EventTypeNormal , util .VolumeModifySuccess , fmt .Sprintf ("external resizer modified volume %s with vac %s successfully" , pvc .Name , vacObj .Name ))
125
141
return pvc , pv , nil , true
0 commit comments