diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index 91e2d3436ac..a9898326dbf 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -27,6 +27,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/klog/v2" "k8s.io/kubernetes/pkg/features" @@ -211,10 +212,11 @@ func NewActualStateOfWorld( nodeName types.NodeName, volumePluginMgr *volume.VolumePluginMgr) ActualStateOfWorld { return &actualStateOfWorld{ - nodeName: nodeName, - attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume), - foundDuringReconstruction: make(map[v1.UniqueVolumeName]map[volumetypes.UniquePodName]types.UID), - volumePluginMgr: volumePluginMgr, + nodeName: nodeName, + attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume), + foundDuringReconstruction: make(map[v1.UniqueVolumeName]map[volumetypes.UniquePodName]types.UID), + volumePluginMgr: volumePluginMgr, + volumesWithFinalExpansionErrors: sets.New[string](), } } @@ -247,6 +249,8 @@ type actualStateOfWorld struct { // from kubelet root directory when kubelet was restarted. foundDuringReconstruction map[v1.UniqueVolumeName]map[volumetypes.UniquePodName]types.UID + volumesWithFinalExpansionErrors sets.Set[v1.UniqueVolumeName] + // volumePluginMgr is the volume plugin manager used to create volume // plugin objects. volumePluginMgr *volume.VolumePluginMgr @@ -396,6 +400,27 @@ func (asw *actualStateOfWorld) MarkVolumeAsDetached( asw.DeleteVolume(volumeName) } +func (asw *actualStateOfWorld) MarkVolumeExpansionFailedWithFinalError(volumeName v1.UniqueVolumeName) { + asw.Lock() + defer asw.Unlock() + + asw.volumesWithFinalExpansionErrors.Insert(volumeName) +} + +func (asw *actualStateOfWorld) RemoveVolumeFromFailedWithFinalErrors(volumeName v1.UniqueVolumeName) { + asw.Lock() + defer asw.Unlock() + + asw.volumesWithFinalExpansionErrors.Delete(volumeName) +} + +func (asw *actualStateOfWorld) CheckVolumeInFailedExpansionWithFinalErrors(volumeName v1.UniqueVolumeName) bool { + asw.RLock() + defer asw.RUnlock() + + return asw.volumesWithFinalExpansionErrors.Has(volumeName) +} + func (asw *actualStateOfWorld) IsVolumeReconstructed(volumeName v1.UniqueVolumeName, podName volumetypes.UniquePodName) bool { volumeState := asw.GetVolumeMountState(volumeName, podName) diff --git a/pkg/volume/util/operationexecutor/operation_executor.go b/pkg/volume/util/operationexecutor/operation_executor.go index 85646de50b2..eaca8ca2282 100644 --- a/pkg/volume/util/operationexecutor/operation_executor.go +++ b/pkg/volume/util/operationexecutor/operation_executor.go @@ -233,6 +233,18 @@ type ActualStateOfWorldMounterUpdater interface { // IsVolumeDeviceReconstructed returns true if volume device identified by volumeName has been // found during reconstruction. IsVolumeDeviceReconstructed(volumeName v1.UniqueVolumeName) bool + + // MarkVolumeExpansionFailedWithFinalError marks volume as failed with a final error, so as + // this state doesn't have to be recorded in the API server + MarkVolumeExpansionFailedWithFinalError(volumeName v1.UniqueVolumeName) + + // RemoveVolumeFromFailedWithFinalErrors removes volume from list that indicates that volume + // has failed expansion with a final error + RemoveVolumeFromFailedWithFinalErrors(volumeName v1.UniqueVolumeName) + + // CheckVolumeInFailedExpansionWithFinalErrors verifies if volume expansion has failed with a final + // error + CheckVolumeInFailedExpansionWithFinalErrors(volumeName v1.UniqueVolumeName) bool } // ActualStateOfWorldAttacherUpdater defines a set of operations updating the