From c8d9863a3e6815a00ab34d377942a696c7d99848 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Mon, 15 Jul 2024 10:14:57 -0400 Subject: [PATCH] Add new type for infeasible errors --- .../cache/actual_state_of_world.go | 2 +- pkg/volume/csi/expander.go | 27 +++++++++++++++++++ pkg/volume/util/types/types.go | 21 +++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go index a9898326dbf..38017a588f7 100644 --- a/pkg/kubelet/volumemanager/cache/actual_state_of_world.go +++ b/pkg/kubelet/volumemanager/cache/actual_state_of_world.go @@ -216,7 +216,7 @@ func NewActualStateOfWorld( attachedVolumes: make(map[v1.UniqueVolumeName]attachedVolume), foundDuringReconstruction: make(map[v1.UniqueVolumeName]map[volumetypes.UniquePodName]types.UID), volumePluginMgr: volumePluginMgr, - volumesWithFinalExpansionErrors: sets.New[string](), + volumesWithFinalExpansionErrors: sets.New[v1.UniqueVolumeName](), } } diff --git a/pkg/volume/csi/expander.go b/pkg/volume/csi/expander.go index d6aae060101..f5e6738434c 100644 --- a/pkg/volume/csi/expander.go +++ b/pkg/volume/csi/expander.go @@ -119,6 +119,11 @@ func (c *csiPlugin) nodeExpandWithClient( failedConditionErr := fmt.Errorf("Expander.NodeExpand failed to expand the volume : %w", volumetypes.NewFailedPreconditionError(err.Error())) return false, failedConditionErr } + + if isInfeasibleError(err) { + infeasibleError := fmt.Errorf("Expander.NodeExpand failed to expand the volume: %w", volumetypes.NewInfeasibleError(err.Error())) + return false, infeasibleError + } return false, fmt.Errorf("Expander.NodeExpand failed to expand the volume : %w", err) } return true, nil @@ -135,3 +140,25 @@ func inUseError(err error) bool { // More info - https://github.com/container-storage-interface/spec/blob/master/spec.md#controllerexpandvolume-errors return st.Code() == codes.FailedPrecondition } + +// IsInfeasibleError returns true for grpc errors that are considered terminal in a way +// that they indicate CSI operation as infeasible. +// This function returns a subset of final errors. All infeasible errors are also final errors. +func isInfeasibleError(err error) bool { + st, ok := status.FromError(err) + if !ok { + // This is not gRPC error. The operation must have failed before gRPC + // method was called, otherwise we would get gRPC error. + // We don't know if any previous volume operation is in progress, be on the safe side. + return false + } + switch st.Code() { + case codes.InvalidArgument, + codes.OutOfRange, + codes.NotFound: + return true + } + // All other errors mean that operation either did not + // even start or failed. It is for sure are not infeasible errors + return false +} diff --git a/pkg/volume/util/types/types.go b/pkg/volume/util/types/types.go index 238e919b331..316962f8f5d 100644 --- a/pkg/volume/util/types/types.go +++ b/pkg/volume/util/types/types.go @@ -102,6 +102,27 @@ func IsFailedPreconditionError(err error) bool { return errors.As(err, &failedPreconditionError) } +// InfeasibleError errors are a subset of OperationFinished or final error +// codes. In terms of CSI - this usually means that, the operation is not possible +// in current state with given arguments. +type InfeasibleError struct { + msg string +} + +func (err *InfeasibleError) Error() string { + return err.msg +} + +// NewInfeasibleError returns a new instance of InfeasibleError +func NewInfeasibleError(msg string) *InfeasibleError { + return &InfeasibleError{msg: msg} +} + +func IsInfeasibleError(err error) bool { + var infeasibleError *InfeasibleError + return errors.As(err, &infeasibleError) +} + type OperationNotSupported struct { msg string }