mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-21 01:26:28 +00:00
Update code to use new generic allocatedResourceStatus field
This commit is contained in:
parent
56f6030125
commit
e011187114
@ -99,7 +99,7 @@ func DropDisabledFieldsFromStatus(pvc, oldPVC *core.PersistentVolumeClaim) {
|
|||||||
pvc.Status.AllocatedResources = nil
|
pvc.Status.AllocatedResources = nil
|
||||||
}
|
}
|
||||||
if !resizeStatusInUse(oldPVC) {
|
if !resizeStatusInUse(oldPVC) {
|
||||||
pvc.Status.ResizeStatus = nil
|
pvc.Status.AllocatedResourceStatuses = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ func resizeStatusInUse(oldPVC *core.PersistentVolumeClaim) bool {
|
|||||||
if oldPVC == nil {
|
if oldPVC == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if oldPVC.Status.ResizeStatus != nil {
|
if oldPVC.Status.AllocatedResourceStatuses != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -436,30 +436,30 @@ func TestDropDisabledFieldsFromStatus(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "for:newPVC=hasResizeStatus,oldPVC=nil, featuregate=false should drop field",
|
name: "for:newPVC=hasResizeStatus,oldPVC=nil, featuregate=false should drop field",
|
||||||
feature: false,
|
feature: false,
|
||||||
pvc: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
pvc: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
oldPVC: nil,
|
oldPVC: nil,
|
||||||
expected: getPVC(),
|
expected: getPVC(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "for:newPVC=hasResizeStatus,oldPVC=doesnot,featuregate=true; should keep field",
|
name: "for:newPVC=hasResizeStatus,oldPVC=doesnot,featuregate=true; should keep field",
|
||||||
feature: true,
|
feature: true,
|
||||||
pvc: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
pvc: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
oldPVC: getPVC(),
|
oldPVC: getPVC(),
|
||||||
expected: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
expected: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "for:newPVC=hasResizeStatus,oldPVC=hasResizeStatus,featuregate=true; should keep field",
|
name: "for:newPVC=hasResizeStatus,oldPVC=hasResizeStatus,featuregate=true; should keep field",
|
||||||
feature: true,
|
feature: true,
|
||||||
pvc: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
pvc: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
oldPVC: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
oldPVC: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
expected: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
expected: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "for:newPVC=hasResizeStatus,oldPVC=hasResizeStatus,featuregate=false; should keep field",
|
name: "for:newPVC=hasResizeStatus,oldPVC=hasResizeStatus,featuregate=false; should keep field",
|
||||||
feature: false,
|
feature: false,
|
||||||
pvc: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
pvc: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
oldPVC: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
oldPVC: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
expected: withResizeStatus(core.PersistentVolumeClaimNodeExpansionFailed),
|
expected: withResizeStatus(core.PersistentVolumeClaimNodeResizeFailed),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,10 +490,12 @@ func withAllocatedResource(q string) *core.PersistentVolumeClaim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func withResizeStatus(status core.PersistentVolumeClaimResizeStatus) *core.PersistentVolumeClaim {
|
func withResizeStatus(status core.ClaimResourceStatus) *core.PersistentVolumeClaim {
|
||||||
return &core.PersistentVolumeClaim{
|
return &core.PersistentVolumeClaim{
|
||||||
Status: core.PersistentVolumeClaimStatus{
|
Status: core.PersistentVolumeClaimStatus{
|
||||||
ResizeStatus: &status,
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
core.ResourceStorage: status,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,23 +515,26 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// +enum
|
// +enum
|
||||||
type PersistentVolumeClaimResizeStatus string
|
// When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource
|
||||||
|
// that it does not recognizes, then it should ignore that update and let other controllers
|
||||||
|
// handle it.
|
||||||
|
type ClaimResourceStatus string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// When expansion is complete, the empty string is set by resize controller or kubelet.
|
|
||||||
PersistentVolumeClaimNoExpansionInProgress PersistentVolumeClaimResizeStatus = ""
|
|
||||||
// State set when resize controller starts expanding the volume in control-plane
|
// State set when resize controller starts expanding the volume in control-plane
|
||||||
PersistentVolumeClaimControllerExpansionInProgress PersistentVolumeClaimResizeStatus = "ControllerExpansionInProgress"
|
PersistentVolumeClaimControllerResizeInProgress ClaimResourceStatus = "ControllerResizeInProgress"
|
||||||
|
|
||||||
// State set when expansion has failed in resize controller with a terminal error.
|
// State set when expansion has failed in resize controller with a terminal error.
|
||||||
// Transient errors such as timeout should not set this status and should leave ResizeStatus
|
// Transient errors such as timeout should not set this status and should leave allocatedResourceStatus
|
||||||
// unmodified, so as resize controller can resume the volume expansion.
|
// unmodified, so as resize controller can resume the volume expansion.
|
||||||
PersistentVolumeClaimControllerExpansionFailed PersistentVolumeClaimResizeStatus = "ControllerExpansionFailed"
|
PersistentVolumeClaimControllerResizeFailed ClaimResourceStatus = "ControllerResizeFailed"
|
||||||
|
|
||||||
// State set when resize controller has finished expanding the volume but further expansion is needed on the node.
|
// State set when resize controller has finished expanding the volume but further expansion is needed on the node.
|
||||||
PersistentVolumeClaimNodeExpansionPending PersistentVolumeClaimResizeStatus = "NodeExpansionPending"
|
PersistentVolumeClaimNodeResizePending ClaimResourceStatus = "NodeResizePending"
|
||||||
// State set when kubelet starts expanding the volume.
|
// State set when kubelet starts expanding the volume.
|
||||||
PersistentVolumeClaimNodeExpansionInProgress PersistentVolumeClaimResizeStatus = "NodeExpansionInProgress"
|
PersistentVolumeClaimNodeResizeInProgress ClaimResourceStatus = "NodeResizeInProgress"
|
||||||
// State set when expansion has failed in kubelet with a terminal error. Transient errors don't set NodeExpansionFailed.
|
// State set when expansion has failed in kubelet with a terminal error. Transient errors don't set NodeExpansionFailed.
|
||||||
PersistentVolumeClaimNodeExpansionFailed PersistentVolumeClaimResizeStatus = "NodeExpansionFailed"
|
PersistentVolumeClaimNodeResizeFailed ClaimResourceStatus = "NodeResizeFailed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PersistentVolumeClaimCondition represents the current condition of PV claim
|
// PersistentVolumeClaimCondition represents the current condition of PV claim
|
||||||
@ -572,13 +575,19 @@ type PersistentVolumeClaimStatus struct {
|
|||||||
// +featureGate=RecoverVolumeExpansionFailure
|
// +featureGate=RecoverVolumeExpansionFailure
|
||||||
// +optional
|
// +optional
|
||||||
AllocatedResources ResourceList
|
AllocatedResources ResourceList
|
||||||
// ResizeStatus stores status of resize operation.
|
// allocatedResourceStatuses stores status of resource being resized for the given PVC.
|
||||||
// ResizeStatus is not set by default but when expansion is complete resizeStatus is set to empty
|
// If Expanding a PVC for more capacity - this field can be one of the following states:
|
||||||
// string by resize controller or kubelet.
|
// - pvc.status.allocatedResourceStatus['storage'] = "ControllerResizeInProgress"
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "ControllerResizeFailed"
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "NodeResizePending"
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "NodeResizeInProgress"
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "NodeResizeFailed"
|
||||||
|
// When this field is not set, it means that no resize operation is in progress for the given PVC.
|
||||||
// This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature.
|
// This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature.
|
||||||
// +featureGate=RecoverVolumeExpansionFailure
|
// +featureGate=RecoverVolumeExpansionFailure
|
||||||
|
// +mapType=granular
|
||||||
// +optional
|
// +optional
|
||||||
ResizeStatus *PersistentVolumeClaimResizeStatus
|
AllocatedResourceStatuses map[ResourceName]ClaimResourceStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
// PersistentVolumeAccessMode defines various access modes for PV.
|
// PersistentVolumeAccessMode defines various access modes for PV.
|
||||||
|
@ -2294,12 +2294,29 @@ func validateStorageClassUpgradeFromNil(oldAnnotations map[string]string, oldScN
|
|||||||
(!oldAnnotationExist || *newScName == oldAnnotation) /* condition 3 */
|
(!oldAnnotationExist || *newScName == oldAnnotation) /* condition 3 */
|
||||||
}
|
}
|
||||||
|
|
||||||
var resizeStatusSet = sets.NewString(string(core.PersistentVolumeClaimNoExpansionInProgress),
|
func validatePersistentVolumeClaimResourceKey(value string, fldPath *field.Path) field.ErrorList {
|
||||||
string(core.PersistentVolumeClaimControllerExpansionInProgress),
|
allErrs := field.ErrorList{}
|
||||||
string(core.PersistentVolumeClaimControllerExpansionFailed),
|
for _, msg := range validation.IsQualifiedName(value) {
|
||||||
string(core.PersistentVolumeClaimNodeExpansionPending),
|
allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
|
||||||
string(core.PersistentVolumeClaimNodeExpansionInProgress),
|
}
|
||||||
string(core.PersistentVolumeClaimNodeExpansionFailed))
|
if len(allErrs) != 0 {
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
// For native resource names such as - either unprefixed names or with kubernetes.io prefix,
|
||||||
|
// only allowed value is storage
|
||||||
|
if helper.IsNativeResource(core.ResourceName(value)) {
|
||||||
|
if core.ResourceName(value) != core.ResourceStorage {
|
||||||
|
return append(allErrs, field.NotSupported(fldPath, value, []string{string(core.ResourceStorage)}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
var resizeStatusSet = sets.NewString(string(core.PersistentVolumeClaimControllerResizeInProgress),
|
||||||
|
string(core.PersistentVolumeClaimControllerResizeFailed),
|
||||||
|
string(core.PersistentVolumeClaimNodeResizePending),
|
||||||
|
string(core.PersistentVolumeClaimNodeResizeInProgress),
|
||||||
|
string(core.PersistentVolumeClaimNodeResizeFailed))
|
||||||
|
|
||||||
// ValidatePersistentVolumeClaimStatusUpdate validates an update to status of a PersistentVolumeClaim
|
// ValidatePersistentVolumeClaimStatusUpdate validates an update to status of a PersistentVolumeClaim
|
||||||
func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *core.PersistentVolumeClaim, validationOpts PersistentVolumeClaimSpecValidationOptions) field.ErrorList {
|
func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *core.PersistentVolumeClaim, validationOpts PersistentVolumeClaimSpecValidationOptions) field.ErrorList {
|
||||||
@ -2316,19 +2333,26 @@ func ValidatePersistentVolumeClaimStatusUpdate(newPvc, oldPvc *core.PersistentVo
|
|||||||
allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
|
allErrs = append(allErrs, validateBasicResource(qty, capPath.Key(string(r)))...)
|
||||||
}
|
}
|
||||||
if validationOpts.EnableRecoverFromExpansionFailure {
|
if validationOpts.EnableRecoverFromExpansionFailure {
|
||||||
resizeStatusPath := field.NewPath("status", "resizeStatus")
|
resizeStatusPath := field.NewPath("status", "allocatedResourceStatus")
|
||||||
if newPvc.Status.ResizeStatus != nil {
|
if newPvc.Status.AllocatedResourceStatuses != nil {
|
||||||
resizeStatus := *newPvc.Status.ResizeStatus
|
resizeStatus := newPvc.Status.AllocatedResourceStatuses
|
||||||
if !resizeStatusSet.Has(string(resizeStatus)) {
|
for k, v := range resizeStatus {
|
||||||
allErrs = append(allErrs, field.NotSupported(resizeStatusPath, resizeStatus, resizeStatusSet.List()))
|
if errs := validatePersistentVolumeClaimResourceKey(k.String(), resizeStatusPath); len(errs) > 0 {
|
||||||
|
allErrs = append(allErrs, errs...)
|
||||||
|
}
|
||||||
|
if !resizeStatusSet.Has(string(v)) {
|
||||||
|
allErrs = append(allErrs, field.NotSupported(resizeStatusPath, k, resizeStatusSet.List()))
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allocPath := field.NewPath("status", "allocatedResources")
|
allocPath := field.NewPath("status", "allocatedResources")
|
||||||
for r, qty := range newPvc.Status.AllocatedResources {
|
for r, qty := range newPvc.Status.AllocatedResources {
|
||||||
if r != core.ResourceStorage {
|
if errs := validatePersistentVolumeClaimResourceKey(r.String(), allocPath); len(errs) > 0 {
|
||||||
allErrs = append(allErrs, field.NotSupported(allocPath, r, []string{string(core.ResourceStorage)}))
|
allErrs = append(allErrs, errs...)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if errs := validateBasicResource(qty, allocPath.Key(string(r))); len(errs) > 0 {
|
if errs := validateBasicResource(qty, allocPath.Key(string(r))); len(errs) > 0 {
|
||||||
allErrs = append(allErrs, errs...)
|
allErrs = append(allErrs, errs...)
|
||||||
} else {
|
} else {
|
||||||
|
@ -18305,15 +18305,60 @@ func TestValidatePersistentVolumeClaimStatusUpdate(t *testing.T) {
|
|||||||
core.ResourceName(core.ResourceCPU): resource.MustParse("10G"),
|
core.ResourceName(core.ResourceCPU): resource.MustParse("10G"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
progressResizeStatus := core.PersistentVolumeClaimControllerExpansionInProgress
|
progressResizeStatus := core.PersistentVolumeClaimControllerResizeInProgress
|
||||||
invalidResizeStatus := core.PersistentVolumeClaimResizeStatus("foo")
|
|
||||||
|
invalidResizeStatus := core.ClaimResourceStatus("foo")
|
||||||
|
validResizeKeyCustom := core.ResourceName("example.com/foo")
|
||||||
|
invalidNativeResizeKey := core.ResourceName("kubernetes.io/foo")
|
||||||
|
|
||||||
validResizeStatusPVC := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
validResizeStatusPVC := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
AccessModes: []core.PersistentVolumeAccessMode{
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
core.ReadWriteOnce,
|
core.ReadWriteOnce,
|
||||||
},
|
},
|
||||||
}, core.PersistentVolumeClaimStatus{
|
}, core.PersistentVolumeClaimStatus{
|
||||||
ResizeStatus: &progressResizeStatus,
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
core.ResourceStorage: progressResizeStatus,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
validResizeStatusControllerResizeFailed := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadWriteOnce,
|
||||||
|
},
|
||||||
|
}, core.PersistentVolumeClaimStatus{
|
||||||
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
core.ResourceStorage: core.PersistentVolumeClaimControllerResizeFailed,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
validNodeResizePending := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadWriteOnce,
|
||||||
|
},
|
||||||
|
}, core.PersistentVolumeClaimStatus{
|
||||||
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
core.ResourceStorage: core.PersistentVolumeClaimNodeResizePending,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
validNodeResizeInProgress := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadWriteOnce,
|
||||||
|
},
|
||||||
|
}, core.PersistentVolumeClaimStatus{
|
||||||
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
core.ResourceStorage: core.PersistentVolumeClaimNodeResizeInProgress,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
validNodeResizeFailed := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadWriteOnce,
|
||||||
|
},
|
||||||
|
}, core.PersistentVolumeClaimStatus{
|
||||||
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
core.ResourceStorage: core.PersistentVolumeClaimNodeResizeFailed,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
invalidResizeStatusPVC := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
invalidResizeStatusPVC := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
@ -18321,7 +18366,69 @@ func TestValidatePersistentVolumeClaimStatusUpdate(t *testing.T) {
|
|||||||
core.ReadWriteOnce,
|
core.ReadWriteOnce,
|
||||||
},
|
},
|
||||||
}, core.PersistentVolumeClaimStatus{
|
}, core.PersistentVolumeClaimStatus{
|
||||||
ResizeStatus: &invalidResizeStatus,
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
core.ResourceStorage: invalidResizeStatus,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
invalidNativeResizeStatusPVC := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadWriteOnce,
|
||||||
|
},
|
||||||
|
}, core.PersistentVolumeClaimStatus{
|
||||||
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
invalidNativeResizeKey: core.PersistentVolumeClaimNodeResizePending,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
validExternalResizeStatusPVC := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadWriteOnce,
|
||||||
|
},
|
||||||
|
}, core.PersistentVolumeClaimStatus{
|
||||||
|
AllocatedResourceStatuses: map[core.ResourceName]core.ClaimResourceStatus{
|
||||||
|
validResizeKeyCustom: core.PersistentVolumeClaimNodeResizePending,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
invalidNativeResourceAllocatedKey := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadWriteOnce,
|
||||||
|
core.ReadOnlyMany,
|
||||||
|
},
|
||||||
|
Resources: core.ResourceRequirements{
|
||||||
|
Requests: core.ResourceList{
|
||||||
|
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, core.PersistentVolumeClaimStatus{
|
||||||
|
Phase: core.ClaimPending,
|
||||||
|
Conditions: []core.PersistentVolumeClaimCondition{
|
||||||
|
{Type: core.PersistentVolumeClaimResizing, Status: core.ConditionTrue},
|
||||||
|
},
|
||||||
|
AllocatedResources: core.ResourceList{
|
||||||
|
invalidNativeResizeKey: resource.MustParse("14G"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
validExternalAllocatedResource := testVolumeClaimWithStatus("foo", "ns", core.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []core.PersistentVolumeAccessMode{
|
||||||
|
core.ReadWriteOnce,
|
||||||
|
core.ReadOnlyMany,
|
||||||
|
},
|
||||||
|
Resources: core.ResourceRequirements{
|
||||||
|
Requests: core.ResourceList{
|
||||||
|
core.ResourceName(core.ResourceStorage): resource.MustParse("10G"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, core.PersistentVolumeClaimStatus{
|
||||||
|
Phase: core.ClaimPending,
|
||||||
|
Conditions: []core.PersistentVolumeClaimCondition{
|
||||||
|
{Type: core.PersistentVolumeClaimResizing, Status: core.ConditionTrue},
|
||||||
|
},
|
||||||
|
AllocatedResources: core.ResourceList{
|
||||||
|
validResizeKeyCustom: resource.MustParse("14G"),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
scenarios := map[string]struct {
|
scenarios := map[string]struct {
|
||||||
@ -18344,6 +18451,21 @@ func TestValidatePersistentVolumeClaimStatusUpdate(t *testing.T) {
|
|||||||
enableResize: true,
|
enableResize: true,
|
||||||
enableRecoverFromExpansion: true,
|
enableRecoverFromExpansion: true,
|
||||||
},
|
},
|
||||||
|
"status-update-with-invalid-allocatedResources-native-key-feature-enabled": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldClaim: validClaim,
|
||||||
|
newClaim: invalidNativeResourceAllocatedKey,
|
||||||
|
enableResize: true,
|
||||||
|
enableRecoverFromExpansion: true,
|
||||||
|
},
|
||||||
|
"status-update-with-valid-allocatedResources-external-key-feature-enabled": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validClaim,
|
||||||
|
newClaim: validExternalAllocatedResource,
|
||||||
|
enableResize: true,
|
||||||
|
enableRecoverFromExpansion: true,
|
||||||
|
},
|
||||||
|
|
||||||
"status-update-with-invalid-allocatedResources-feature-enabled": {
|
"status-update-with-invalid-allocatedResources-feature-enabled": {
|
||||||
isExpectedFailure: true,
|
isExpectedFailure: true,
|
||||||
oldClaim: validClaim,
|
oldClaim: validClaim,
|
||||||
@ -18358,6 +18480,48 @@ func TestValidatePersistentVolumeClaimStatusUpdate(t *testing.T) {
|
|||||||
enableResize: true,
|
enableResize: true,
|
||||||
enableRecoverFromExpansion: true,
|
enableRecoverFromExpansion: true,
|
||||||
},
|
},
|
||||||
|
"staus-update-with-controller-resize-failed": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validClaim,
|
||||||
|
newClaim: validResizeStatusControllerResizeFailed,
|
||||||
|
enableResize: true,
|
||||||
|
enableRecoverFromExpansion: true,
|
||||||
|
},
|
||||||
|
"staus-update-with-node-resize-pending": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validClaim,
|
||||||
|
newClaim: validNodeResizePending,
|
||||||
|
enableResize: true,
|
||||||
|
enableRecoverFromExpansion: true,
|
||||||
|
},
|
||||||
|
"staus-update-with-node-resize-inprogress": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validClaim,
|
||||||
|
newClaim: validNodeResizeInProgress,
|
||||||
|
enableResize: true,
|
||||||
|
enableRecoverFromExpansion: true,
|
||||||
|
},
|
||||||
|
"staus-update-with-node-resize-failed": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validClaim,
|
||||||
|
newClaim: validNodeResizeFailed,
|
||||||
|
enableResize: true,
|
||||||
|
enableRecoverFromExpansion: true,
|
||||||
|
},
|
||||||
|
"staus-update-with-invalid-native-resource-status-key": {
|
||||||
|
isExpectedFailure: true,
|
||||||
|
oldClaim: validClaim,
|
||||||
|
newClaim: invalidNativeResizeStatusPVC,
|
||||||
|
enableResize: true,
|
||||||
|
enableRecoverFromExpansion: true,
|
||||||
|
},
|
||||||
|
"staus-update-with-valid-external-resource-status-key": {
|
||||||
|
isExpectedFailure: false,
|
||||||
|
oldClaim: validClaim,
|
||||||
|
newClaim: validExternalResizeStatusPVC,
|
||||||
|
enableResize: true,
|
||||||
|
enableRecoverFromExpansion: true,
|
||||||
|
},
|
||||||
"status-update-with-valid-pvc-resize-status": {
|
"status-update-with-valid-pvc-resize-status": {
|
||||||
isExpectedFailure: false,
|
isExpectedFailure: false,
|
||||||
oldClaim: validClaim,
|
oldClaim: validClaim,
|
||||||
|
@ -587,7 +587,7 @@ func (dsw *desiredStateOfWorld) GetVolumesToMount() []VolumeToMount {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
if volumeObj.persistentVolumeSize != nil {
|
if volumeObj.persistentVolumeSize != nil {
|
||||||
vmt.PersistentVolumeSize = volumeObj.persistentVolumeSize.DeepCopy()
|
vmt.DesiredPersistentVolumeSize = volumeObj.persistentVolumeSize.DeepCopy()
|
||||||
}
|
}
|
||||||
volumesToMount = append(volumesToMount, vmt)
|
volumesToMount = append(volumesToMount, vmt)
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ func (rc *reconciler) unmountVolumes() {
|
|||||||
func (rc *reconciler) mountOrAttachVolumes() {
|
func (rc *reconciler) mountOrAttachVolumes() {
|
||||||
// Ensure volumes that should be attached/mounted are attached/mounted.
|
// Ensure volumes that should be attached/mounted are attached/mounted.
|
||||||
for _, volumeToMount := range rc.desiredStateOfWorld.GetVolumesToMount() {
|
for _, volumeToMount := range rc.desiredStateOfWorld.GetVolumesToMount() {
|
||||||
volMounted, devicePath, err := rc.actualStateOfWorld.PodExistsInVolume(volumeToMount.PodName, volumeToMount.VolumeName, volumeToMount.PersistentVolumeSize, volumeToMount.SELinuxLabel)
|
volMounted, devicePath, err := rc.actualStateOfWorld.PodExistsInVolume(volumeToMount.PodName, volumeToMount.VolumeName, volumeToMount.DesiredPersistentVolumeSize, volumeToMount.SELinuxLabel)
|
||||||
volumeToMount.DevicePath = devicePath
|
volumeToMount.DevicePath = devicePath
|
||||||
if cache.IsSELinuxMountMismatchError(err) {
|
if cache.IsSELinuxMountMismatchError(err) {
|
||||||
// The volume is mounted, but with an unexpected SELinux context.
|
// The volume is mounted, but with an unexpected SELinux context.
|
||||||
|
@ -37,7 +37,7 @@ type NodeExpander struct {
|
|||||||
// computed via precheck
|
// computed via precheck
|
||||||
pvcStatusCap resource.Quantity
|
pvcStatusCap resource.Quantity
|
||||||
pvCap resource.Quantity
|
pvCap resource.Quantity
|
||||||
resizeStatus *v1.PersistentVolumeClaimResizeStatus
|
resizeStatus v1.ClaimResourceStatus
|
||||||
|
|
||||||
// pvcAlreadyUpdated if true indicates that although we are calling NodeExpandVolume on the kubelet
|
// pvcAlreadyUpdated if true indicates that although we are calling NodeExpandVolume on the kubelet
|
||||||
// PVC has already been updated - possibly because expansion already succeeded on different node.
|
// PVC has already been updated - possibly because expansion already succeeded on different node.
|
||||||
@ -68,29 +68,37 @@ type testResponseData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// runPreCheck performs some sanity checks before expansion can be performed on the PVC.
|
// runPreCheck performs some sanity checks before expansion can be performed on the PVC.
|
||||||
|
// This function returns true only if node expansion is allowed to proceed otherwise
|
||||||
|
// it returns false.
|
||||||
func (ne *NodeExpander) runPreCheck() bool {
|
func (ne *NodeExpander) runPreCheck() bool {
|
||||||
ne.pvcStatusCap = ne.pvc.Status.Capacity[v1.ResourceStorage]
|
ne.pvcStatusCap = ne.pvc.Status.Capacity[v1.ResourceStorage]
|
||||||
ne.pvCap = ne.pv.Spec.Capacity[v1.ResourceStorage]
|
ne.pvCap = ne.pv.Spec.Capacity[v1.ResourceStorage]
|
||||||
|
|
||||||
ne.resizeStatus = ne.pvc.Status.ResizeStatus
|
allocatedResourceStatus := ne.pvc.Status.AllocatedResourceStatuses
|
||||||
|
if currentStatus, ok := allocatedResourceStatus[v1.ResourceStorage]; ok {
|
||||||
|
ne.resizeStatus = currentStatus
|
||||||
|
}
|
||||||
|
|
||||||
// PVC is already expanded but we are still trying to expand the volume because
|
// PVC is already expanded but we are still trying to expand the volume because
|
||||||
// last recorded size in ASOW is older. This can happen for RWX volume types.
|
// last recorded size in ASOW is older. This can happen for RWX volume types.
|
||||||
if ne.pvcStatusCap.Cmp(ne.pluginResizeOpts.NewSize) >= 0 && (ne.resizeStatus == nil || *ne.resizeStatus == v1.PersistentVolumeClaimNoExpansionInProgress) {
|
if ne.pvcStatusCap.Cmp(ne.pluginResizeOpts.NewSize) >= 0 && ne.resizeStatus == "" {
|
||||||
ne.pvcAlreadyUpdated = true
|
ne.pvcAlreadyUpdated = true
|
||||||
}
|
|
||||||
|
|
||||||
// if resizestatus is nil or NodeExpansionInProgress or NodeExpansionPending then we
|
|
||||||
// should allow volume expansion on the node to proceed. We are making an exception for
|
|
||||||
// resizeStatus being nil because it will support use cases where
|
|
||||||
// resizeStatus may not be set (old control-plane expansion controller etc).
|
|
||||||
if ne.resizeStatus == nil ||
|
|
||||||
ne.pvcAlreadyUpdated ||
|
|
||||||
*ne.resizeStatus == v1.PersistentVolumeClaimNodeExpansionPending ||
|
|
||||||
*ne.resizeStatus == v1.PersistentVolumeClaimNodeExpansionInProgress {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// recovery features will only work for newer version of resize controller
|
||||||
|
if ne.resizeStatus == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeStatusVal := ne.resizeStatus
|
||||||
|
|
||||||
|
// if resizestatus is nil or NodeExpansionInProgress or NodeExpansionPending then we
|
||||||
|
// should allow volume expansion on the node to proceed.
|
||||||
|
if resizeStatusVal == v1.PersistentVolumeClaimNodeResizePending ||
|
||||||
|
resizeStatusVal == v1.PersistentVolumeClaimNodeResizeInProgress {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
package operationexecutor
|
package operationexecutor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
@ -24,10 +26,12 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/features"
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
volumetesting "k8s.io/kubernetes/pkg/volume/testing"
|
volumetesting "k8s.io/kubernetes/pkg/volume/testing"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNodeExpander(t *testing.T) {
|
func TestNodeExpander(t *testing.T) {
|
||||||
|
nodeResizeFailed := v1.PersistentVolumeClaimNodeResizeFailed
|
||||||
|
|
||||||
|
nodeResizePending := v1.PersistentVolumeClaimNodeResizePending
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
pvc *v1.PersistentVolumeClaim
|
pvc *v1.PersistentVolumeClaim
|
||||||
@ -39,7 +43,7 @@ func TestNodeExpander(t *testing.T) {
|
|||||||
actualSize *resource.Quantity
|
actualSize *resource.Quantity
|
||||||
|
|
||||||
// expectations of test
|
// expectations of test
|
||||||
expectedResizeStatus v1.PersistentVolumeClaimResizeStatus
|
expectedResizeStatus v1.ClaimResourceStatus
|
||||||
expectedStatusSize resource.Quantity
|
expectedStatusSize resource.Quantity
|
||||||
expectResizeCall bool
|
expectResizeCall bool
|
||||||
assumeResizeOpAsFinished bool
|
assumeResizeOpAsFinished bool
|
||||||
@ -47,39 +51,39 @@ func TestNodeExpander(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_failed",
|
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_failed",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "1G", "", v1.PersistentVolumeClaimNodeExpansionFailed),
|
pvc: getTestPVC("test-vol0", "2G", "1G", "", &nodeResizeFailed),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
|
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionFailed,
|
expectedResizeStatus: nodeResizeFailed,
|
||||||
expectResizeCall: false,
|
expectResizeCall: false,
|
||||||
assumeResizeOpAsFinished: true,
|
assumeResizeOpAsFinished: true,
|
||||||
expectedStatusSize: resource.MustParse("1G"),
|
expectedStatusSize: resource.MustParse("1G"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_pending",
|
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_pending",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "1G", "2G", v1.PersistentVolumeClaimNodeExpansionPending),
|
pvc: getTestPVC("test-vol0", "2G", "1G", "2G", &nodeResizePending),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNoExpansionInProgress,
|
expectedResizeStatus: "",
|
||||||
expectResizeCall: true,
|
expectResizeCall: true,
|
||||||
assumeResizeOpAsFinished: true,
|
assumeResizeOpAsFinished: true,
|
||||||
expectedStatusSize: resource.MustParse("2G"),
|
expectedStatusSize: resource.MustParse("2G"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_pending, reize_op=failing",
|
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_pending, reize_op=failing",
|
||||||
pvc: getTestPVC(volumetesting.AlwaysFailNodeExpansion, "2G", "1G", "2G", v1.PersistentVolumeClaimNodeExpansionPending),
|
pvc: getTestPVC(volumetesting.AlwaysFailNodeExpansion, "2G", "1G", "2G", &nodeResizePending),
|
||||||
pv: getTestPV(volumetesting.AlwaysFailNodeExpansion, "2G"),
|
pv: getTestPV(volumetesting.AlwaysFailNodeExpansion, "2G"),
|
||||||
expectError: true,
|
expectError: true,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionFailed,
|
expectedResizeStatus: nodeResizeFailed,
|
||||||
expectResizeCall: true,
|
expectResizeCall: true,
|
||||||
assumeResizeOpAsFinished: true,
|
assumeResizeOpAsFinished: true,
|
||||||
expectedStatusSize: resource.MustParse("1G"),
|
expectedStatusSize: resource.MustParse("1G"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap = pvc.status.cap, resizeStatus='', desiredSize > actualSize",
|
name: "pv.spec.cap = pvc.status.cap, resizeStatus='', desiredSize > actualSize",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "2G", "2G", v1.PersistentVolumeClaimNoExpansionInProgress),
|
pvc: getTestPVC("test-vol0", "2G", "2G", "2G", nil),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
|
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNoExpansionInProgress,
|
expectedResizeStatus: "",
|
||||||
expectResizeCall: true,
|
expectResizeCall: true,
|
||||||
assumeResizeOpAsFinished: true,
|
assumeResizeOpAsFinished: true,
|
||||||
expectedStatusSize: resource.MustParse("2G"),
|
expectedStatusSize: resource.MustParse("2G"),
|
||||||
@ -143,8 +147,11 @@ func TestNodeExpander(t *testing.T) {
|
|||||||
if test.assumeResizeOpAsFinished != expansionResponse.assumeResizeFinished {
|
if test.assumeResizeOpAsFinished != expansionResponse.assumeResizeFinished {
|
||||||
t.Errorf("For test %s, expected assumeResizeOpAsFinished %t, got %t", test.name, test.assumeResizeOpAsFinished, expansionResponse.assumeResizeFinished)
|
t.Errorf("For test %s, expected assumeResizeOpAsFinished %t, got %t", test.name, test.assumeResizeOpAsFinished, expansionResponse.assumeResizeFinished)
|
||||||
}
|
}
|
||||||
if test.expectedResizeStatus != *pvc.Status.ResizeStatus {
|
allocatedResourceStatus := pvc.Status.AllocatedResourceStatuses
|
||||||
t.Errorf("For test %s, expected resizeStatus %v, got %v", test.name, test.expectedResizeStatus, *pvc.Status.ResizeStatus)
|
resizeStatus := allocatedResourceStatus[v1.ResourceStorage]
|
||||||
|
|
||||||
|
if test.expectedResizeStatus != resizeStatus {
|
||||||
|
t.Errorf("For test %s, expected resizeStatus %v, got %v", test.name, test.expectedResizeStatus, resizeStatus)
|
||||||
}
|
}
|
||||||
if pvcStatusCap.Cmp(test.expectedStatusSize) != 0 {
|
if pvcStatusCap.Cmp(test.expectedStatusSize) != 0 {
|
||||||
t.Errorf("For test %s, expected status size %s, got %s", test.name, test.expectedStatusSize.String(), pvcStatusCap.String())
|
t.Errorf("For test %s, expected status size %s, got %s", test.name, test.expectedStatusSize.String(), pvcStatusCap.String())
|
||||||
|
@ -440,9 +440,9 @@ type VolumeToMount struct {
|
|||||||
// time at which volume was requested to be mounted
|
// time at which volume was requested to be mounted
|
||||||
MountRequestTime time.Time
|
MountRequestTime time.Time
|
||||||
|
|
||||||
// PersistentVolumeSize stores desired size of the volume.
|
// DesiredPersistentVolumeSize stores desired size of the volume.
|
||||||
// usually this is the size if pv.Spec.Capacity
|
// usually this is the size if pv.Spec.Capacity
|
||||||
PersistentVolumeSize resource.Quantity
|
DesiredPersistentVolumeSize resource.Quantity
|
||||||
|
|
||||||
// SELinux label that should be used to mount.
|
// SELinux label that should be used to mount.
|
||||||
SELinuxLabel string
|
SELinuxLabel string
|
||||||
|
@ -1781,12 +1781,14 @@ func (og *operationGenerator) expandAndRecoverFunction(resizeOpts inTreeResizeOp
|
|||||||
resizeCalled: false,
|
resizeCalled: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
// by default we are expanding to full-fill size requested in pvc.Spec.Resources
|
// by default we are expanding to fulfill size requested in pvc.Spec.Resources
|
||||||
newSize := pvcSpecSize
|
newSize := pvcSpecSize
|
||||||
resizeStatus := v1.PersistentVolumeClaimNoExpansionInProgress
|
|
||||||
if pvc.Status.ResizeStatus != nil {
|
var resizeStatus v1.ClaimResourceStatus
|
||||||
resizeStatus = *pvc.Status.ResizeStatus
|
if status, ok := pvc.Status.AllocatedResourceStatuses[v1.ResourceStorage]; ok {
|
||||||
|
resizeStatus = status
|
||||||
}
|
}
|
||||||
|
|
||||||
var allocatedSize *resource.Quantity
|
var allocatedSize *resource.Quantity
|
||||||
t, ok := pvc.Status.AllocatedResources[v1.ResourceStorage]
|
t, ok := pvc.Status.AllocatedResources[v1.ResourceStorage]
|
||||||
if ok {
|
if ok {
|
||||||
@ -1798,10 +1800,10 @@ func (og *operationGenerator) expandAndRecoverFunction(resizeOpts inTreeResizeOp
|
|||||||
// pv is not of requested size yet and hence will require expanding
|
// pv is not of requested size yet and hence will require expanding
|
||||||
|
|
||||||
switch resizeStatus {
|
switch resizeStatus {
|
||||||
case v1.PersistentVolumeClaimControllerExpansionInProgress:
|
case v1.PersistentVolumeClaimControllerResizeInProgress,
|
||||||
case v1.PersistentVolumeClaimNodeExpansionPending:
|
v1.PersistentVolumeClaimNodeResizePending,
|
||||||
case v1.PersistentVolumeClaimNodeExpansionInProgress:
|
v1.PersistentVolumeClaimNodeResizeInProgress,
|
||||||
case v1.PersistentVolumeClaimNodeExpansionFailed:
|
v1.PersistentVolumeClaimNodeResizeFailed:
|
||||||
if allocatedSize != nil {
|
if allocatedSize != nil {
|
||||||
newSize = *allocatedSize
|
newSize = *allocatedSize
|
||||||
}
|
}
|
||||||
@ -1820,30 +1822,29 @@ func (og *operationGenerator) expandAndRecoverFunction(resizeOpts inTreeResizeOp
|
|||||||
// safe to do so.
|
// safe to do so.
|
||||||
// 4. While expansion was still pending on the node, user reduced the pvc size.
|
// 4. While expansion was still pending on the node, user reduced the pvc size.
|
||||||
switch resizeStatus {
|
switch resizeStatus {
|
||||||
case v1.PersistentVolumeClaimNodeExpansionInProgress:
|
case v1.PersistentVolumeClaimNodeResizeInProgress,
|
||||||
case v1.PersistentVolumeClaimNodeExpansionPending:
|
v1.PersistentVolumeClaimNodeResizePending:
|
||||||
// we don't need to do any work. We could be here because of a spurious update event.
|
// we don't need to do any work. We could be here because of a spurious update event.
|
||||||
// This is case #1
|
// This is case #1
|
||||||
return resizeResponse
|
return resizeResponse
|
||||||
case v1.PersistentVolumeClaimNodeExpansionFailed:
|
case v1.PersistentVolumeClaimNodeResizeFailed:
|
||||||
// This is case#3
|
// This is case#3
|
||||||
pvc, err = og.markForPendingNodeExpansion(pvc, pv)
|
pvc, err = og.markForPendingNodeExpansion(pvc, pv)
|
||||||
resizeResponse.pvc = pvc
|
resizeResponse.pvc = pvc
|
||||||
resizeResponse.err = err
|
resizeResponse.err = err
|
||||||
return resizeResponse
|
return resizeResponse
|
||||||
case v1.PersistentVolumeClaimControllerExpansionInProgress:
|
case v1.PersistentVolumeClaimControllerResizeInProgress,
|
||||||
case v1.PersistentVolumeClaimControllerExpansionFailed:
|
v1.PersistentVolumeClaimControllerResizeFailed:
|
||||||
case v1.PersistentVolumeClaimNoExpansionInProgress:
|
|
||||||
// This is case#2 or it could also be case#4 when user manually shrunk the PVC
|
// This is case#2 or it could also be case#4 when user manually shrunk the PVC
|
||||||
// after expanding it.
|
// after expanding it.
|
||||||
if allocatedSize != nil {
|
if allocatedSize != nil {
|
||||||
newSize = *allocatedSize
|
newSize = *allocatedSize
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// It is impossible for ResizeStatus to be nil and allocatedSize to be not nil but somehow
|
// It is impossible for ResizeStatus to be "" and allocatedSize to be not nil but somehow
|
||||||
// if we do end up in this state, it is safest to resume expansion to last recorded size in
|
// if we do end up in this state, it is safest to resume expansion to last recorded size in
|
||||||
// allocatedSize variable.
|
// allocatedSize variable.
|
||||||
if pvc.Status.ResizeStatus == nil && allocatedSize != nil {
|
if resizeStatus == "" && allocatedSize != nil {
|
||||||
newSize = *allocatedSize
|
newSize = *allocatedSize
|
||||||
} else {
|
} else {
|
||||||
newSize = pvcSpecSize
|
newSize = pvcSpecSize
|
||||||
@ -1938,7 +1939,7 @@ func (og *operationGenerator) GenerateExpandInUseVolumeFunc(
|
|||||||
var eventErr, detailedErr error
|
var eventErr, detailedErr error
|
||||||
migrated := false
|
migrated := false
|
||||||
|
|
||||||
if currentSize.IsZero() || volumeToMount.PersistentVolumeSize.IsZero() {
|
if currentSize.IsZero() || volumeToMount.DesiredPersistentVolumeSize.IsZero() {
|
||||||
err := fmt.Errorf("current or new size of the volume is not set")
|
err := fmt.Errorf("current or new size of the volume is not set")
|
||||||
eventErr, detailedErr = volumeToMount.GenerateError("NodeExpandvolume.expansion failed", err)
|
eventErr, detailedErr = volumeToMount.GenerateError("NodeExpandvolume.expansion failed", err)
|
||||||
return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
|
return volumetypes.NewOperationContext(eventErr, detailedErr, migrated)
|
||||||
@ -1948,7 +1949,7 @@ func (og *operationGenerator) GenerateExpandInUseVolumeFunc(
|
|||||||
VolumeSpec: volumeToMount.VolumeSpec,
|
VolumeSpec: volumeToMount.VolumeSpec,
|
||||||
DevicePath: volumeToMount.DevicePath,
|
DevicePath: volumeToMount.DevicePath,
|
||||||
OldSize: currentSize,
|
OldSize: currentSize,
|
||||||
NewSize: volumeToMount.PersistentVolumeSize,
|
NewSize: volumeToMount.DesiredPersistentVolumeSize,
|
||||||
}
|
}
|
||||||
fsVolume, err := util.CheckVolumeModeFilesystem(volumeToMount.VolumeSpec)
|
fsVolume, err := util.CheckVolumeModeFilesystem(volumeToMount.VolumeSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -2168,7 +2169,7 @@ func (og *operationGenerator) nodeExpandVolume(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (og *operationGenerator) checkForRecoveryFromExpansion(pvc *v1.PersistentVolumeClaim, volumeToMount VolumeToMount) bool {
|
func (og *operationGenerator) checkForRecoveryFromExpansion(pvc *v1.PersistentVolumeClaim, volumeToMount VolumeToMount) bool {
|
||||||
resizeStatus := pvc.Status.ResizeStatus
|
resizeStatus := pvc.Status.AllocatedResourceStatuses[v1.ResourceStorage]
|
||||||
allocatedResource := pvc.Status.AllocatedResources
|
allocatedResource := pvc.Status.AllocatedResources
|
||||||
featureGateStatus := utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure)
|
featureGateStatus := utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure)
|
||||||
|
|
||||||
@ -2179,7 +2180,7 @@ func (og *operationGenerator) checkForRecoveryFromExpansion(pvc *v1.PersistentVo
|
|||||||
// Even though RecoverVolumeExpansionFailure feature gate is enabled, it appears that we are running with older version
|
// Even though RecoverVolumeExpansionFailure feature gate is enabled, it appears that we are running with older version
|
||||||
// of resize controller, which will not populate allocatedResource and resizeStatus. This can happen because of version skew
|
// of resize controller, which will not populate allocatedResource and resizeStatus. This can happen because of version skew
|
||||||
// and hence we are going to keep expanding using older logic.
|
// and hence we are going to keep expanding using older logic.
|
||||||
if resizeStatus == nil && allocatedResource == nil {
|
if resizeStatus == "" && allocatedResource == nil {
|
||||||
_, detailedMsg := volumeToMount.GenerateMsg("MountVolume.NodeExpandVolume running with", "older external resize controller")
|
_, detailedMsg := volumeToMount.GenerateMsg("MountVolume.NodeExpandVolume running with", "older external resize controller")
|
||||||
klog.Warningf(detailedMsg)
|
klog.Warningf(detailedMsg)
|
||||||
return false
|
return false
|
||||||
|
@ -93,6 +93,8 @@ func TestOperationGenerator_GenerateUnmapVolumeFunc_PluginName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOperationGenerator_GenerateExpandAndRecoverVolumeFunc(t *testing.T) {
|
func TestOperationGenerator_GenerateExpandAndRecoverVolumeFunc(t *testing.T) {
|
||||||
|
nodeResizePending := v1.PersistentVolumeClaimNodeResizePending
|
||||||
|
nodeResizeFailed := v1.PersistentVolumeClaimNodeResizeFailed
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
pvc *v1.PersistentVolumeClaim
|
pvc *v1.PersistentVolumeClaim
|
||||||
@ -100,53 +102,53 @@ func TestOperationGenerator_GenerateExpandAndRecoverVolumeFunc(t *testing.T) {
|
|||||||
recoverFeatureGate bool
|
recoverFeatureGate bool
|
||||||
disableNodeExpansion bool
|
disableNodeExpansion bool
|
||||||
// expectations of test
|
// expectations of test
|
||||||
expectedResizeStatus v1.PersistentVolumeClaimResizeStatus
|
expectedResizeStatus v1.ClaimResourceStatus
|
||||||
expectedAllocatedSize resource.Quantity
|
expectedAllocatedSize resource.Quantity
|
||||||
expectResizeCall bool
|
expectResizeCall bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pvc.spec.size > pv.spec.size, recover_expansion=on",
|
name: "pvc.spec.size > pv.spec.size, recover_expansion=on",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "1G", "", v1.PersistentVolumeClaimNoExpansionInProgress),
|
pvc: getTestPVC("test-vol0", "2G", "1G", "", nil),
|
||||||
pv: getTestPV("test-vol0", "1G"),
|
pv: getTestPV("test-vol0", "1G"),
|
||||||
recoverFeatureGate: true,
|
recoverFeatureGate: true,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionPending,
|
expectedResizeStatus: v1.PersistentVolumeClaimNodeResizePending,
|
||||||
expectedAllocatedSize: resource.MustParse("2G"),
|
expectedAllocatedSize: resource.MustParse("2G"),
|
||||||
expectResizeCall: true,
|
expectResizeCall: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pvc.spec.size = pv.spec.size, recover_expansion=on",
|
name: "pvc.spec.size = pv.spec.size, recover_expansion=on",
|
||||||
pvc: getTestPVC("test-vol0", "1G", "1G", "", v1.PersistentVolumeClaimNoExpansionInProgress),
|
pvc: getTestPVC("test-vol0", "1G", "1G", "", nil),
|
||||||
pv: getTestPV("test-vol0", "1G"),
|
pv: getTestPV("test-vol0", "1G"),
|
||||||
recoverFeatureGate: true,
|
recoverFeatureGate: true,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionPending,
|
expectedResizeStatus: v1.PersistentVolumeClaimNodeResizePending,
|
||||||
expectedAllocatedSize: resource.MustParse("1G"),
|
expectedAllocatedSize: resource.MustParse("1G"),
|
||||||
expectResizeCall: true,
|
expectResizeCall: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pvc.spec.size = pv.spec.size, recover_expansion=on",
|
name: "pvc.spec.size = pv.spec.size, recover_expansion=on",
|
||||||
pvc: getTestPVC("test-vol0", "1G", "1G", "1G", v1.PersistentVolumeClaimNodeExpansionPending),
|
pvc: getTestPVC("test-vol0", "1G", "1G", "1G", &nodeResizePending),
|
||||||
pv: getTestPV("test-vol0", "1G"),
|
pv: getTestPV("test-vol0", "1G"),
|
||||||
recoverFeatureGate: true,
|
recoverFeatureGate: true,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionPending,
|
expectedResizeStatus: v1.PersistentVolumeClaimNodeResizePending,
|
||||||
expectedAllocatedSize: resource.MustParse("1G"),
|
expectedAllocatedSize: resource.MustParse("1G"),
|
||||||
expectResizeCall: false,
|
expectResizeCall: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pvc.spec.size > pv.spec.size, recover_expansion=on, disable_node_expansion=true",
|
name: "pvc.spec.size > pv.spec.size, recover_expansion=on, disable_node_expansion=true",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "1G", "", v1.PersistentVolumeClaimNoExpansionInProgress),
|
pvc: getTestPVC("test-vol0", "2G", "1G", "", nil),
|
||||||
pv: getTestPV("test-vol0", "1G"),
|
pv: getTestPV("test-vol0", "1G"),
|
||||||
disableNodeExpansion: true,
|
disableNodeExpansion: true,
|
||||||
recoverFeatureGate: true,
|
recoverFeatureGate: true,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNoExpansionInProgress,
|
expectedResizeStatus: "",
|
||||||
expectedAllocatedSize: resource.MustParse("2G"),
|
expectedAllocatedSize: resource.MustParse("2G"),
|
||||||
expectResizeCall: true,
|
expectResizeCall: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.size >= pvc.spec.size, recover_expansion=on, resize_status=node_expansion_failed",
|
name: "pv.spec.size >= pvc.spec.size, recover_expansion=on, resize_status=node_expansion_failed",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "1G", "2G", v1.PersistentVolumeClaimNodeExpansionFailed),
|
pvc: getTestPVC("test-vol0", "2G", "1G", "2G", &nodeResizeFailed),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
recoverFeatureGate: true,
|
recoverFeatureGate: true,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionPending,
|
expectedResizeStatus: v1.PersistentVolumeClaimNodeResizePending,
|
||||||
expectedAllocatedSize: resource.MustParse("2G"),
|
expectedAllocatedSize: resource.MustParse("2G"),
|
||||||
expectResizeCall: false,
|
expectResizeCall: false,
|
||||||
},
|
},
|
||||||
@ -173,7 +175,8 @@ func TestOperationGenerator_GenerateExpandAndRecoverVolumeFunc(t *testing.T) {
|
|||||||
t.Fatalf("GenerateExpandAndRecoverVolumeFunc failed: %v", expansionResponse.err)
|
t.Fatalf("GenerateExpandAndRecoverVolumeFunc failed: %v", expansionResponse.err)
|
||||||
}
|
}
|
||||||
updatedPVC := expansionResponse.pvc
|
updatedPVC := expansionResponse.pvc
|
||||||
assert.Equal(t, *updatedPVC.Status.ResizeStatus, test.expectedResizeStatus)
|
actualResizeStatus := updatedPVC.Status.AllocatedResourceStatuses[v1.ResourceStorage]
|
||||||
|
assert.Equal(t, actualResizeStatus, test.expectedResizeStatus)
|
||||||
actualAllocatedSize := updatedPVC.Status.AllocatedResources.Storage()
|
actualAllocatedSize := updatedPVC.Status.AllocatedResources.Storage()
|
||||||
if test.expectedAllocatedSize.Cmp(*actualAllocatedSize) != 0 {
|
if test.expectedAllocatedSize.Cmp(*actualAllocatedSize) != 0 {
|
||||||
t.Fatalf("GenerateExpandAndRecoverVolumeFunc failed: expected allocated size %s, got %s", test.expectedAllocatedSize.String(), actualAllocatedSize.String())
|
t.Fatalf("GenerateExpandAndRecoverVolumeFunc failed: expected allocated size %s, got %s", test.expectedAllocatedSize.String(), actualAllocatedSize.String())
|
||||||
@ -191,6 +194,8 @@ func TestOperationGenerator_nodeExpandVolume(t *testing.T) {
|
|||||||
return &x
|
return &x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodeResizeFailed := v1.PersistentVolumeClaimNodeResizeFailed
|
||||||
|
nodeResizePending := v1.PersistentVolumeClaimNodeResizePending
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
pvc *v1.PersistentVolumeClaim
|
pvc *v1.PersistentVolumeClaim
|
||||||
@ -202,65 +207,65 @@ func TestOperationGenerator_nodeExpandVolume(t *testing.T) {
|
|||||||
actualSize *resource.Quantity
|
actualSize *resource.Quantity
|
||||||
|
|
||||||
// expectations of test
|
// expectations of test
|
||||||
expectedResizeStatus v1.PersistentVolumeClaimResizeStatus
|
expectedResizeStatus v1.ClaimResourceStatus
|
||||||
expectedStatusSize resource.Quantity
|
expectedStatusSize resource.Quantity
|
||||||
resizeCallCount int
|
resizeCallCount int
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_failed",
|
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_failed",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "1G", "", v1.PersistentVolumeClaimNodeExpansionFailed),
|
pvc: getTestPVC("test-vol0", "2G", "1G", "", &nodeResizeFailed),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
|
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionFailed,
|
expectedResizeStatus: v1.PersistentVolumeClaimNodeResizeFailed,
|
||||||
resizeCallCount: 0,
|
resizeCallCount: 0,
|
||||||
expectedStatusSize: resource.MustParse("1G"),
|
expectedStatusSize: resource.MustParse("1G"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_pending",
|
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_pending",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "1G", "2G", v1.PersistentVolumeClaimNodeExpansionPending),
|
pvc: getTestPVC("test-vol0", "2G", "1G", "2G", &nodeResizePending),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNoExpansionInProgress,
|
expectedResizeStatus: "",
|
||||||
resizeCallCount: 1,
|
resizeCallCount: 1,
|
||||||
expectedStatusSize: resource.MustParse("2G"),
|
expectedStatusSize: resource.MustParse("2G"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_pending, reize_op=failing",
|
name: "pv.spec.cap > pvc.status.cap, resizeStatus=node_expansion_pending, reize_op=failing",
|
||||||
pvc: getTestPVC(volumetesting.AlwaysFailNodeExpansion, "2G", "1G", "2G", v1.PersistentVolumeClaimNodeExpansionPending),
|
pvc: getTestPVC(volumetesting.AlwaysFailNodeExpansion, "2G", "1G", "2G", &nodeResizePending),
|
||||||
pv: getTestPV(volumetesting.AlwaysFailNodeExpansion, "2G"),
|
pv: getTestPV(volumetesting.AlwaysFailNodeExpansion, "2G"),
|
||||||
expectError: true,
|
expectError: true,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionFailed,
|
expectedResizeStatus: v1.PersistentVolumeClaimNodeResizeFailed,
|
||||||
resizeCallCount: 1,
|
resizeCallCount: 1,
|
||||||
expectedStatusSize: resource.MustParse("1G"),
|
expectedStatusSize: resource.MustParse("1G"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap = pvc.status.cap, resizeStatus='', desiredSize = actualSize",
|
name: "pv.spec.cap = pvc.status.cap, resizeStatus='', desiredSize = actualSize",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "2G", "2G", v1.PersistentVolumeClaimNoExpansionInProgress),
|
pvc: getTestPVC("test-vol0", "2G", "2G", "2G", nil),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
|
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNoExpansionInProgress,
|
expectedResizeStatus: "",
|
||||||
resizeCallCount: 0,
|
resizeCallCount: 0,
|
||||||
expectedStatusSize: resource.MustParse("2G"),
|
expectedStatusSize: resource.MustParse("2G"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap = pvc.status.cap, resizeStatus='', desiredSize > actualSize",
|
name: "pv.spec.cap = pvc.status.cap, resizeStatus='', desiredSize > actualSize",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "2G", "2G", v1.PersistentVolumeClaimNoExpansionInProgress),
|
pvc: getTestPVC("test-vol0", "2G", "2G", "2G", nil),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
desiredSize: getSizeFunc("2G"),
|
desiredSize: getSizeFunc("2G"),
|
||||||
actualSize: getSizeFunc("1G"),
|
actualSize: getSizeFunc("1G"),
|
||||||
|
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNoExpansionInProgress,
|
expectedResizeStatus: "",
|
||||||
resizeCallCount: 1,
|
resizeCallCount: 1,
|
||||||
expectedStatusSize: resource.MustParse("2G"),
|
expectedStatusSize: resource.MustParse("2G"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pv.spec.cap = pvc.status.cap, resizeStatus=node-expansion-failed, desiredSize > actualSize",
|
name: "pv.spec.cap = pvc.status.cap, resizeStatus=node-expansion-failed, desiredSize > actualSize",
|
||||||
pvc: getTestPVC("test-vol0", "2G", "2G", "2G", v1.PersistentVolumeClaimNodeExpansionFailed),
|
pvc: getTestPVC("test-vol0", "2G", "2G", "2G", &nodeResizeFailed),
|
||||||
pv: getTestPV("test-vol0", "2G"),
|
pv: getTestPV("test-vol0", "2G"),
|
||||||
desiredSize: getSizeFunc("2G"),
|
desiredSize: getSizeFunc("2G"),
|
||||||
actualSize: getSizeFunc("1G"),
|
actualSize: getSizeFunc("1G"),
|
||||||
|
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionFailed,
|
expectedResizeStatus: v1.PersistentVolumeClaimNodeResizeFailed,
|
||||||
resizeCallCount: 0,
|
resizeCallCount: 0,
|
||||||
expectedStatusSize: resource.MustParse("2G"),
|
expectedStatusSize: resource.MustParse("2G"),
|
||||||
},
|
},
|
||||||
@ -336,7 +341,7 @@ func getTestPod(podName, pvcName string) *v1.Pod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTestPVC(volumeName string, specSize, statusSize, allocatedSize string, resizeStatus v1.PersistentVolumeClaimResizeStatus) *v1.PersistentVolumeClaim {
|
func getTestPVC(volumeName string, specSize, statusSize, allocatedSize string, resizeStatus *v1.ClaimResourceStatus) *v1.PersistentVolumeClaim {
|
||||||
pvc := &v1.PersistentVolumeClaim{
|
pvc := &v1.PersistentVolumeClaim{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "claim01",
|
Name: "claim01",
|
||||||
@ -358,7 +363,11 @@ func getTestPVC(volumeName string, specSize, statusSize, allocatedSize string, r
|
|||||||
if len(allocatedSize) > 0 {
|
if len(allocatedSize) > 0 {
|
||||||
pvc.Status.AllocatedResources = v1.ResourceList{v1.ResourceStorage: resource.MustParse(allocatedSize)}
|
pvc.Status.AllocatedResources = v1.ResourceList{v1.ResourceStorage: resource.MustParse(allocatedSize)}
|
||||||
}
|
}
|
||||||
pvc.Status.ResizeStatus = &resizeStatus
|
if resizeStatus != nil {
|
||||||
|
pvc.Status.AllocatedResourceStatuses = map[v1.ResourceName]v1.ClaimResourceStatus{
|
||||||
|
v1.ResourceStorage: *resizeStatus,
|
||||||
|
}
|
||||||
|
}
|
||||||
return pvc
|
return pvc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,12 +152,11 @@ func MarkControllerReisizeInProgress(pvc *v1.PersistentVolumeClaim, resizerName
|
|||||||
Status: v1.ConditionTrue,
|
Status: v1.ConditionTrue,
|
||||||
LastTransitionTime: metav1.Now(),
|
LastTransitionTime: metav1.Now(),
|
||||||
}
|
}
|
||||||
controllerExpansionInProgress := v1.PersistentVolumeClaimControllerExpansionInProgress
|
|
||||||
conditions := []v1.PersistentVolumeClaimCondition{progressCondition}
|
conditions := []v1.PersistentVolumeClaimCondition{progressCondition}
|
||||||
newPVC := pvc.DeepCopy()
|
newPVC := pvc.DeepCopy()
|
||||||
newPVC = MergeResizeConditionOnPVC(newPVC, conditions)
|
newPVC = MergeResizeConditionOnPVC(newPVC, conditions)
|
||||||
newPVC.Status.ResizeStatus = &controllerExpansionInProgress
|
newPVC = mergeStorageResourceStatus(newPVC, v1.PersistentVolumeClaimControllerResizeInProgress)
|
||||||
newPVC.Status.AllocatedResources = v1.ResourceList{v1.ResourceStorage: newSize}
|
newPVC = mergeStorageAllocatedResources(newPVC, newSize)
|
||||||
newPVC = setResizer(newPVC, resizerName)
|
newPVC = setResizer(newPVC, resizerName)
|
||||||
return PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient)
|
return PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient)
|
||||||
}
|
}
|
||||||
@ -192,10 +191,11 @@ func MarkForFSResize(
|
|||||||
}
|
}
|
||||||
conditions := []v1.PersistentVolumeClaimCondition{pvcCondition}
|
conditions := []v1.PersistentVolumeClaimCondition{pvcCondition}
|
||||||
newPVC := pvc.DeepCopy()
|
newPVC := pvc.DeepCopy()
|
||||||
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure) {
|
||||||
expansionPendingOnNode := v1.PersistentVolumeClaimNodeExpansionPending
|
newPVC = mergeStorageResourceStatus(newPVC, v1.PersistentVolumeClaimNodeResizePending)
|
||||||
newPVC.Status.ResizeStatus = &expansionPendingOnNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newPVC = MergeResizeConditionOnPVC(newPVC, conditions)
|
newPVC = MergeResizeConditionOnPVC(newPVC, conditions)
|
||||||
updatedPVC, err := PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient)
|
updatedPVC, err := PatchPVCStatus(pvc /*oldPVC*/, newPVC, kubeClient)
|
||||||
return updatedPVC, err
|
return updatedPVC, err
|
||||||
@ -220,8 +220,13 @@ func MarkFSResizeFinished(
|
|||||||
|
|
||||||
// if RecoverVolumeExpansionFailure is enabled, we need to reset ResizeStatus back to nil
|
// if RecoverVolumeExpansionFailure is enabled, we need to reset ResizeStatus back to nil
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.RecoverVolumeExpansionFailure) {
|
||||||
expansionFinished := v1.PersistentVolumeClaimNoExpansionInProgress
|
allocatedResourceStatusMap := newPVC.Status.AllocatedResourceStatuses
|
||||||
newPVC.Status.ResizeStatus = &expansionFinished
|
delete(allocatedResourceStatusMap, v1.ResourceStorage)
|
||||||
|
if len(allocatedResourceStatusMap) == 0 {
|
||||||
|
newPVC.Status.AllocatedResourceStatuses = nil
|
||||||
|
} else {
|
||||||
|
newPVC.Status.AllocatedResourceStatuses = allocatedResourceStatusMap
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newPVC = MergeResizeConditionOnPVC(newPVC, []v1.PersistentVolumeClaimCondition{})
|
newPVC = MergeResizeConditionOnPVC(newPVC, []v1.PersistentVolumeClaimCondition{})
|
||||||
@ -232,9 +237,9 @@ func MarkFSResizeFinished(
|
|||||||
// MarkNodeExpansionFailed marks a PVC for node expansion as failed. Kubelet should not retry expansion
|
// MarkNodeExpansionFailed marks a PVC for node expansion as failed. Kubelet should not retry expansion
|
||||||
// of volumes which are in failed state.
|
// of volumes which are in failed state.
|
||||||
func MarkNodeExpansionFailed(pvc *v1.PersistentVolumeClaim, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) {
|
func MarkNodeExpansionFailed(pvc *v1.PersistentVolumeClaim, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) {
|
||||||
expansionFailedOnNode := v1.PersistentVolumeClaimNodeExpansionFailed
|
|
||||||
newPVC := pvc.DeepCopy()
|
newPVC := pvc.DeepCopy()
|
||||||
newPVC.Status.ResizeStatus = &expansionFailedOnNode
|
newPVC = mergeStorageResourceStatus(newPVC, v1.PersistentVolumeClaimNodeResizeFailed)
|
||||||
|
|
||||||
patchBytes, err := createPVCPatch(pvc, newPVC, false /* addResourceVersionCheck */)
|
patchBytes, err := createPVCPatch(pvc, newPVC, false /* addResourceVersionCheck */)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pvc, fmt.Errorf("patchPVCStatus failed to patch PVC %q: %v", pvc.Name, err)
|
return pvc, fmt.Errorf("patchPVCStatus failed to patch PVC %q: %v", pvc.Name, err)
|
||||||
@ -250,9 +255,8 @@ func MarkNodeExpansionFailed(pvc *v1.PersistentVolumeClaim, kubeClient clientset
|
|||||||
|
|
||||||
// MarkNodeExpansionInProgress marks pvc expansion in progress on node
|
// MarkNodeExpansionInProgress marks pvc expansion in progress on node
|
||||||
func MarkNodeExpansionInProgress(pvc *v1.PersistentVolumeClaim, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) {
|
func MarkNodeExpansionInProgress(pvc *v1.PersistentVolumeClaim, kubeClient clientset.Interface) (*v1.PersistentVolumeClaim, error) {
|
||||||
nodeExpansionInProgress := v1.PersistentVolumeClaimNodeExpansionInProgress
|
|
||||||
newPVC := pvc.DeepCopy()
|
newPVC := pvc.DeepCopy()
|
||||||
newPVC.Status.ResizeStatus = &nodeExpansionInProgress
|
newPVC = mergeStorageResourceStatus(newPVC, v1.PersistentVolumeClaimNodeResizeInProgress)
|
||||||
updatedPVC, err := PatchPVCStatus(pvc /* oldPVC */, newPVC, kubeClient)
|
updatedPVC, err := PatchPVCStatus(pvc /* oldPVC */, newPVC, kubeClient)
|
||||||
return updatedPVC, err
|
return updatedPVC, err
|
||||||
}
|
}
|
||||||
@ -365,6 +369,32 @@ func MergeResizeConditionOnPVC(
|
|||||||
return pvc
|
return pvc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mergeStorageResourceStatus(pvc *v1.PersistentVolumeClaim, status v1.ClaimResourceStatus) *v1.PersistentVolumeClaim {
|
||||||
|
allocatedResourceStatusMap := pvc.Status.AllocatedResourceStatuses
|
||||||
|
if allocatedResourceStatusMap == nil {
|
||||||
|
pvc.Status.AllocatedResourceStatuses = map[v1.ResourceName]v1.ClaimResourceStatus{
|
||||||
|
v1.ResourceStorage: status,
|
||||||
|
}
|
||||||
|
return pvc
|
||||||
|
}
|
||||||
|
allocatedResourceStatusMap[v1.ResourceStorage] = status
|
||||||
|
pvc.Status.AllocatedResourceStatuses = allocatedResourceStatusMap
|
||||||
|
return pvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeStorageAllocatedResources(pvc *v1.PersistentVolumeClaim, size resource.Quantity) *v1.PersistentVolumeClaim {
|
||||||
|
allocatedResourcesMap := pvc.Status.AllocatedResources
|
||||||
|
if allocatedResourcesMap == nil {
|
||||||
|
pvc.Status.AllocatedResources = map[v1.ResourceName]resource.Quantity{
|
||||||
|
v1.ResourceStorage: size,
|
||||||
|
}
|
||||||
|
return pvc
|
||||||
|
}
|
||||||
|
allocatedResourcesMap[v1.ResourceStorage] = size
|
||||||
|
pvc.Status.AllocatedResources = allocatedResourcesMap
|
||||||
|
return pvc
|
||||||
|
}
|
||||||
|
|
||||||
// GenericResizeFS : call generic filesystem resizer for plugins that don't have any special filesystem resize requirements
|
// GenericResizeFS : call generic filesystem resizer for plugins that don't have any special filesystem resize requirements
|
||||||
func GenericResizeFS(host volume.VolumeHost, pluginName, devicePath, deviceMountPath string) (bool, error) {
|
func GenericResizeFS(host volume.VolumeHost, pluginName, devicePath, deviceMountPath string) (bool, error) {
|
||||||
resizer := mount.NewResizeFs(host.GetExec(pluginName))
|
resizer := mount.NewResizeFs(host.GetExec(pluginName))
|
||||||
|
@ -360,8 +360,8 @@ func (p *Plugin) admitPVCStatus(nodeName string, a admission.Attributes) error {
|
|||||||
newPVC.Status.Conditions = nil
|
newPVC.Status.Conditions = nil
|
||||||
|
|
||||||
if p.expansionRecoveryEnabled {
|
if p.expansionRecoveryEnabled {
|
||||||
oldPVC.Status.ResizeStatus = nil
|
oldPVC.Status.AllocatedResourceStatuses = nil
|
||||||
newPVC.Status.ResizeStatus = nil
|
newPVC.Status.AllocatedResourceStatuses = nil
|
||||||
|
|
||||||
oldPVC.Status.AllocatedResources = nil
|
oldPVC.Status.AllocatedResources = nil
|
||||||
newPVC.Status.AllocatedResources = nil
|
newPVC.Status.AllocatedResources = nil
|
||||||
|
@ -1438,6 +1438,8 @@ func TestAdmitPVCStatus(t *testing.T) {
|
|||||||
noExistingPods := corev1lister.NewPodLister(noExistingPodsIndex)
|
noExistingPods := corev1lister.NewPodLister(noExistingPodsIndex)
|
||||||
mynode := &user.DefaultInfo{Name: "system:node:mynode", Groups: []string{"system:nodes"}}
|
mynode := &user.DefaultInfo{Name: "system:node:mynode", Groups: []string{"system:nodes"}}
|
||||||
|
|
||||||
|
nodeExpansionFailed := api.PersistentVolumeClaimNodeResizeFailed
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
resource schema.GroupVersionResource
|
resource schema.GroupVersionResource
|
||||||
@ -1452,11 +1454,11 @@ func TestAdmitPVCStatus(t *testing.T) {
|
|||||||
name: "should not allow full pvc update from nodes",
|
name: "should not allow full pvc update from nodes",
|
||||||
oldObj: makeTestPVC(
|
oldObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimResizing,
|
api.PersistentVolumeClaimResizing,
|
||||||
api.PersistentVolumeClaimNoExpansionInProgress, "10G",
|
"10G", nil,
|
||||||
),
|
),
|
||||||
subresource: "",
|
subresource: "",
|
||||||
newObj: makeTestPVC(
|
newObj: makeTestPVC(
|
||||||
"", api.PersistentVolumeClaimNoExpansionInProgress, "10G",
|
"", "10G", nil,
|
||||||
),
|
),
|
||||||
expectError: "is forbidden: may only update PVC status",
|
expectError: "is forbidden: may only update PVC status",
|
||||||
},
|
},
|
||||||
@ -1464,13 +1466,13 @@ func TestAdmitPVCStatus(t *testing.T) {
|
|||||||
name: "should allow capacity and condition updates, if expansion is enabled",
|
name: "should allow capacity and condition updates, if expansion is enabled",
|
||||||
oldObj: makeTestPVC(
|
oldObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimResizing,
|
api.PersistentVolumeClaimResizing,
|
||||||
api.PersistentVolumeClaimNoExpansionInProgress, "10G",
|
"10G", nil,
|
||||||
),
|
),
|
||||||
expansionFeatureEnabled: true,
|
expansionFeatureEnabled: true,
|
||||||
subresource: "status",
|
subresource: "status",
|
||||||
newObj: makeTestPVC(
|
newObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimFileSystemResizePending,
|
api.PersistentVolumeClaimFileSystemResizePending,
|
||||||
api.PersistentVolumeClaimNoExpansionInProgress, "10G",
|
"10G", nil,
|
||||||
),
|
),
|
||||||
expectError: "",
|
expectError: "",
|
||||||
},
|
},
|
||||||
@ -1478,13 +1480,13 @@ func TestAdmitPVCStatus(t *testing.T) {
|
|||||||
name: "should not allow updates to allocatedResources with just expansion enabled",
|
name: "should not allow updates to allocatedResources with just expansion enabled",
|
||||||
oldObj: makeTestPVC(
|
oldObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimResizing,
|
api.PersistentVolumeClaimResizing,
|
||||||
api.PersistentVolumeClaimNoExpansionInProgress, "10G",
|
"10G", nil,
|
||||||
),
|
),
|
||||||
subresource: "status",
|
subresource: "status",
|
||||||
expansionFeatureEnabled: true,
|
expansionFeatureEnabled: true,
|
||||||
newObj: makeTestPVC(
|
newObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimFileSystemResizePending,
|
api.PersistentVolumeClaimFileSystemResizePending,
|
||||||
api.PersistentVolumeClaimNoExpansionInProgress, "15G",
|
"15G", nil,
|
||||||
),
|
),
|
||||||
expectError: "is not allowed to update fields other than",
|
expectError: "is not allowed to update fields other than",
|
||||||
},
|
},
|
||||||
@ -1492,14 +1494,14 @@ func TestAdmitPVCStatus(t *testing.T) {
|
|||||||
name: "should allow updates to allocatedResources with expansion and recovery enabled",
|
name: "should allow updates to allocatedResources with expansion and recovery enabled",
|
||||||
oldObj: makeTestPVC(
|
oldObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimResizing,
|
api.PersistentVolumeClaimResizing,
|
||||||
api.PersistentVolumeClaimNoExpansionInProgress, "10G",
|
"10G", nil,
|
||||||
),
|
),
|
||||||
subresource: "status",
|
subresource: "status",
|
||||||
expansionFeatureEnabled: true,
|
expansionFeatureEnabled: true,
|
||||||
recoveryFeatureEnabled: true,
|
recoveryFeatureEnabled: true,
|
||||||
newObj: makeTestPVC(
|
newObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimFileSystemResizePending,
|
api.PersistentVolumeClaimFileSystemResizePending,
|
||||||
api.PersistentVolumeClaimNoExpansionInProgress, "15G",
|
"15G", nil,
|
||||||
),
|
),
|
||||||
expectError: "",
|
expectError: "",
|
||||||
},
|
},
|
||||||
@ -1507,14 +1509,14 @@ func TestAdmitPVCStatus(t *testing.T) {
|
|||||||
name: "should allow updates to resizeStatus with expansion and recovery enabled",
|
name: "should allow updates to resizeStatus with expansion and recovery enabled",
|
||||||
oldObj: makeTestPVC(
|
oldObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimResizing,
|
api.PersistentVolumeClaimResizing,
|
||||||
api.PersistentVolumeClaimNoExpansionInProgress, "10G",
|
"10G", nil,
|
||||||
),
|
),
|
||||||
subresource: "status",
|
subresource: "status",
|
||||||
expansionFeatureEnabled: true,
|
expansionFeatureEnabled: true,
|
||||||
recoveryFeatureEnabled: true,
|
recoveryFeatureEnabled: true,
|
||||||
newObj: makeTestPVC(
|
newObj: makeTestPVC(
|
||||||
api.PersistentVolumeClaimResizing,
|
api.PersistentVolumeClaimResizing,
|
||||||
api.PersistentVolumeClaimNodeExpansionFailed, "10G",
|
"10G", &nodeExpansionFailed,
|
||||||
),
|
),
|
||||||
expectError: "",
|
expectError: "",
|
||||||
},
|
},
|
||||||
@ -1545,8 +1547,8 @@ func TestAdmitPVCStatus(t *testing.T) {
|
|||||||
|
|
||||||
func makeTestPVC(
|
func makeTestPVC(
|
||||||
condition api.PersistentVolumeClaimConditionType,
|
condition api.PersistentVolumeClaimConditionType,
|
||||||
resizeStatus api.PersistentVolumeClaimResizeStatus,
|
allocatedResources string,
|
||||||
allocatedResources string) *api.PersistentVolumeClaim {
|
resizeStatus *api.ClaimResourceStatus) *api.PersistentVolumeClaim {
|
||||||
pvc := &api.PersistentVolumeClaim{
|
pvc := &api.PersistentVolumeClaim{
|
||||||
Spec: api.PersistentVolumeClaimSpec{
|
Spec: api.PersistentVolumeClaimSpec{
|
||||||
VolumeName: "volume1",
|
VolumeName: "volume1",
|
||||||
@ -1560,13 +1562,19 @@ func makeTestPVC(
|
|||||||
Capacity: api.ResourceList{
|
Capacity: api.ResourceList{
|
||||||
api.ResourceStorage: resource.MustParse(allocatedResources),
|
api.ResourceStorage: resource.MustParse(allocatedResources),
|
||||||
},
|
},
|
||||||
Phase: api.ClaimBound,
|
Phase: api.ClaimBound,
|
||||||
ResizeStatus: &resizeStatus,
|
|
||||||
AllocatedResources: api.ResourceList{
|
AllocatedResources: api.ResourceList{
|
||||||
api.ResourceStorage: resource.MustParse(allocatedResources),
|
api.ResourceStorage: resource.MustParse(allocatedResources),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if resizeStatus != nil {
|
||||||
|
claimStatusMap := map[api.ResourceName]api.ClaimResourceStatus{
|
||||||
|
api.ResourceStorage: *resizeStatus,
|
||||||
|
}
|
||||||
|
pvc.Status.AllocatedResourceStatuses = claimStatusMap
|
||||||
|
}
|
||||||
|
|
||||||
if len(condition) > 0 {
|
if len(condition) > 0 {
|
||||||
pvc.Status.Conditions = []api.PersistentVolumeClaimCondition{
|
pvc.Status.Conditions = []api.PersistentVolumeClaimCondition{
|
||||||
{
|
{
|
||||||
|
@ -558,23 +558,23 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// +enum
|
// +enum
|
||||||
type PersistentVolumeClaimResizeStatus string
|
type ClaimResourceStatus string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// When expansion is complete, the empty string is set by resize controller or kubelet.
|
|
||||||
PersistentVolumeClaimNoExpansionInProgress PersistentVolumeClaimResizeStatus = ""
|
|
||||||
// State set when resize controller starts expanding the volume in control-plane
|
// State set when resize controller starts expanding the volume in control-plane
|
||||||
PersistentVolumeClaimControllerExpansionInProgress PersistentVolumeClaimResizeStatus = "ControllerExpansionInProgress"
|
PersistentVolumeClaimControllerResizeInProgress ClaimResourceStatus = "ControllerResizeInProgress"
|
||||||
|
|
||||||
// State set when expansion has failed in resize controller with a terminal error.
|
// State set when expansion has failed in resize controller with a terminal error.
|
||||||
// Transient errors such as timeout should not set this status and should leave ResizeStatus
|
// Transient errors such as timeout should not set this status and should leave allocatedResourceStatus
|
||||||
// unmodified, so as resize controller can resume the volume expansion.
|
// unmodified, so as resize controller can resume the volume expansion.
|
||||||
PersistentVolumeClaimControllerExpansionFailed PersistentVolumeClaimResizeStatus = "ControllerExpansionFailed"
|
PersistentVolumeClaimControllerResizeFailed ClaimResourceStatus = "ControllerResizeFailed"
|
||||||
|
|
||||||
// State set when resize controller has finished expanding the volume but further expansion is needed on the node.
|
// State set when resize controller has finished expanding the volume but further expansion is needed on the node.
|
||||||
PersistentVolumeClaimNodeExpansionPending PersistentVolumeClaimResizeStatus = "NodeExpansionPending"
|
PersistentVolumeClaimNodeResizePending ClaimResourceStatus = "NodeResizePending"
|
||||||
// State set when kubelet starts expanding the volume.
|
// State set when kubelet starts expanding the volume.
|
||||||
PersistentVolumeClaimNodeExpansionInProgress PersistentVolumeClaimResizeStatus = "NodeExpansionInProgress"
|
PersistentVolumeClaimNodeResizeInProgress ClaimResourceStatus = "NodeResizeInProgress"
|
||||||
// State set when expansion has failed in kubelet with a terminal error. Transient errors don't set NodeExpansionFailed.
|
// State set when expansion has failed in kubelet with a terminal error. Transient errors don't set NodeExpansionFailed.
|
||||||
PersistentVolumeClaimNodeExpansionFailed PersistentVolumeClaimResizeStatus = "NodeExpansionFailed"
|
PersistentVolumeClaimNodeResizeFailed ClaimResourceStatus = "NodeResizeFailed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PersistentVolumeClaimCondition contains details about state of pvc
|
// PersistentVolumeClaimCondition contains details about state of pvc
|
||||||
@ -626,13 +626,23 @@ type PersistentVolumeClaimStatus struct {
|
|||||||
// +featureGate=RecoverVolumeExpansionFailure
|
// +featureGate=RecoverVolumeExpansionFailure
|
||||||
// +optional
|
// +optional
|
||||||
AllocatedResources ResourceList `json:"allocatedResources,omitempty" protobuf:"bytes,5,rep,name=allocatedResources,casttype=ResourceList,castkey=ResourceName"`
|
AllocatedResources ResourceList `json:"allocatedResources,omitempty" protobuf:"bytes,5,rep,name=allocatedResources,casttype=ResourceList,castkey=ResourceName"`
|
||||||
// resizeStatus stores status of resize operation.
|
|
||||||
// ResizeStatus is not set by default but when expansion is complete resizeStatus is set to empty
|
// resizestatus is tombstoned since the field was replaced by allocatedResourceStatus
|
||||||
// string by resize controller or kubelet.
|
// ResizeStatus *PersistentVolumeClaimResizeStatus `json:"resizeStatus,omitempty" protobuf:"bytes,6,opt,name=resizeStatus,casttype=PersistentVolumeClaimResizeStatus"`
|
||||||
|
|
||||||
|
// allocatedResourceStatuses stores status of resource being resized for the given PVC.
|
||||||
|
// If Expanding a PVC for more capacity - this field can be one of the following states:
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "ControllerResizeInProgress"
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "ControllerResizeFailed"
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "NodeResizePending"
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "NodeResizeInProgress"
|
||||||
|
// - pvc.status.allocatedResourceStatus['storage'] = "NodeResizeFailed"
|
||||||
|
// When this field is not set, it means that no resize operation is in progress for the given PVC.
|
||||||
// This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature.
|
// This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature.
|
||||||
// +featureGate=RecoverVolumeExpansionFailure
|
// +featureGate=RecoverVolumeExpansionFailure
|
||||||
|
// +mapType=granular
|
||||||
// +optional
|
// +optional
|
||||||
ResizeStatus *PersistentVolumeClaimResizeStatus `json:"resizeStatus,omitempty" protobuf:"bytes,6,opt,name=resizeStatus,casttype=PersistentVolumeClaimResizeStatus"`
|
AllocatedResourceStatuses map[ResourceName]ClaimResourceStatus `json:"allocatedResourceStatuses,omitempty" protobuf:"bytes,7,rep,name=allocatedResourceStatuses"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +enum
|
// +enum
|
||||||
|
@ -63,7 +63,7 @@ type recoveryTest struct {
|
|||||||
pvcRequestSize string
|
pvcRequestSize string
|
||||||
allocatedResource string
|
allocatedResource string
|
||||||
simulatedCSIDriverError expansionStatus
|
simulatedCSIDriverError expansionStatus
|
||||||
expectedResizeStatus v1.PersistentVolumeClaimResizeStatus
|
expectedResizeStatus v1.ClaimResourceStatus
|
||||||
recoverySize resource.Quantity
|
recoverySize resource.Quantity
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,14 +403,14 @@ var _ = utils.SIGDescribe("CSI Mock volume expansion", func() {
|
|||||||
pvcRequestSize: "4Gi",
|
pvcRequestSize: "4Gi",
|
||||||
allocatedResource: "4Gi",
|
allocatedResource: "4Gi",
|
||||||
simulatedCSIDriverError: expansionSuccess,
|
simulatedCSIDriverError: expansionSuccess,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNoExpansionInProgress,
|
expectedResizeStatus: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "should allow recovery if controller expansion fails with final error",
|
name: "should allow recovery if controller expansion fails with final error",
|
||||||
pvcRequestSize: "11Gi", // expansion to 11Gi will cause expansion to fail on controller
|
pvcRequestSize: "11Gi", // expansion to 11Gi will cause expansion to fail on controller
|
||||||
allocatedResource: "11Gi",
|
allocatedResource: "11Gi",
|
||||||
simulatedCSIDriverError: expansionFailedOnController,
|
simulatedCSIDriverError: expansionFailedOnController,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimControllerExpansionFailed,
|
expectedResizeStatus: v1.PersistentVolumeClaimControllerResizeFailed,
|
||||||
recoverySize: resource.MustParse("4Gi"),
|
recoverySize: resource.MustParse("4Gi"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -418,7 +418,7 @@ var _ = utils.SIGDescribe("CSI Mock volume expansion", func() {
|
|||||||
pvcRequestSize: "9Gi", // expansion to 9Gi will cause expansion to fail on node
|
pvcRequestSize: "9Gi", // expansion to 9Gi will cause expansion to fail on node
|
||||||
allocatedResource: "9Gi",
|
allocatedResource: "9Gi",
|
||||||
simulatedCSIDriverError: expansionFailedOnNode,
|
simulatedCSIDriverError: expansionFailedOnNode,
|
||||||
expectedResizeStatus: v1.PersistentVolumeClaimNodeExpansionFailed,
|
expectedResizeStatus: v1.PersistentVolumeClaimNodeResizeFailed,
|
||||||
recoverySize: resource.MustParse("5Gi"),
|
recoverySize: resource.MustParse("5Gi"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -499,7 +499,7 @@ func validateRecoveryBehaviour(ctx context.Context, pvc *v1.PersistentVolumeClai
|
|||||||
// if expansion succeeded on controller but failed on the node
|
// if expansion succeeded on controller but failed on the node
|
||||||
if test.simulatedCSIDriverError == expansionFailedOnNode {
|
if test.simulatedCSIDriverError == expansionFailedOnNode {
|
||||||
ginkgo.By("Wait for expansion to fail on node again")
|
ginkgo.By("Wait for expansion to fail on node again")
|
||||||
err = waitForResizeStatus(pvc, m.cs, v1.PersistentVolumeClaimNodeExpansionFailed)
|
err = waitForResizeStatus(pvc, m.cs, v1.PersistentVolumeClaimNodeResizeFailed)
|
||||||
framework.ExpectNoError(err, "While waiting for resize status to be set to expansion-failed-on-node")
|
framework.ExpectNoError(err, "While waiting for resize status to be set to expansion-failed-on-node")
|
||||||
|
|
||||||
ginkgo.By("verify allocated resources after recovery")
|
ginkgo.By("verify allocated resources after recovery")
|
||||||
@ -536,13 +536,13 @@ func validateExpansionSuccess(ctx context.Context, pvc *v1.PersistentVolumeClaim
|
|||||||
framework.Failf("expected allocated Resources to be %s got %s", expectedAllocatedResource.String(), allocatedResource.String())
|
framework.Failf("expected allocated Resources to be %s got %s", expectedAllocatedResource.String(), allocatedResource.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeStatus := pvc.Status.ResizeStatus
|
resizeStatus := pvc.Status.AllocatedResourceStatuses[v1.ResourceStorage]
|
||||||
gomega.Expect(resizeStatus).NotTo(gomega.BeNil(), "resize status should not be nil")
|
framework.ExpectEqual(resizeStatus, "", "resize status should be empty")
|
||||||
framework.ExpectEqual(*resizeStatus, v1.PersistentVolumeClaimNoExpansionInProgress, "resize status should be empty")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForResizeStatus(pvc *v1.PersistentVolumeClaim, c clientset.Interface, expectedStates ...v1.PersistentVolumeClaimResizeStatus) error {
|
func waitForResizeStatus(pvc *v1.PersistentVolumeClaim, c clientset.Interface, expectedState v1.ClaimResourceStatus) error {
|
||||||
var actualResizeStatus *v1.PersistentVolumeClaimResizeStatus
|
var actualResizeStatus *v1.ClaimResourceStatus
|
||||||
|
|
||||||
waitErr := wait.PollImmediate(resizePollInterval, csiResizeWaitPeriod, func() (bool, error) {
|
waitErr := wait.PollImmediate(resizePollInterval, csiResizeWaitPeriod, func() (bool, error) {
|
||||||
var err error
|
var err error
|
||||||
updatedPVC, err := c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(context.TODO(), pvc.Name, metav1.GetOptions{})
|
updatedPVC, err := c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(context.TODO(), pvc.Name, metav1.GetOptions{})
|
||||||
@ -551,18 +551,11 @@ func waitForResizeStatus(pvc *v1.PersistentVolumeClaim, c clientset.Interface, e
|
|||||||
return false, fmt.Errorf("error fetching pvc %q for checking for resize status: %w", pvc.Name, err)
|
return false, fmt.Errorf("error fetching pvc %q for checking for resize status: %w", pvc.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
actualResizeStatus = updatedPVC.Status.ResizeStatus
|
actualResizeStatus := updatedPVC.Status.AllocatedResourceStatuses[v1.ResourceStorage]
|
||||||
if actualResizeStatus != nil {
|
return (actualResizeStatus == expectedState), nil
|
||||||
for _, s := range expectedStates {
|
|
||||||
if s == *actualResizeStatus {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
})
|
})
|
||||||
if waitErr != nil {
|
if waitErr != nil {
|
||||||
return fmt.Errorf("error while waiting for resize status to sync to %+v, actualStatus %s: %v", expectedStates, *actualResizeStatus, waitErr)
|
return fmt.Errorf("error while waiting for resize status to sync to %v, actualStatus %s: %v", expectedState, *actualResizeStatus, waitErr)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user