Repository: kubernetes-sigs/gcp-compute-persistent-disk-csi-driver
Pull request #1720 (2024-05-23 21:09:26)

Return Unavailable for 'connection reset by peer' errors
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
3. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

**What type of PR is this?**
> Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading whitespaces from that line:
>
> /kind api-change
> /kind bug

/kind cleanup

> /kind design
> /kind documentation
> /kind failing-test
> /kind feature
> /kind flake

**What this PR does / why we need it**:
Return Unavailable for 'connection reset by peer' errors.  Unavailable error code indicates that a CreateVolume operation might be in progress. https://github.com/kubernetes-csi/external-provisioner/blob/master/pkg/controller/controller.go#L1902

**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

**Special notes for your reviewer**:

**Does this PR introduce a user-facing change?**:
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
Return Unavailable for 'connection reset by peer' errors.
```



Patch:
diff --git a/pkg/common/utils.go b/pkg/common/utils.go
index 705d55fd..17a75bd9 100644
--- a/pkg/common/utils.go
+++ b/pkg/common/utils.go
@@ -433,6 +433,9 @@ func CodeForError(sourceError error) codes.Code {
 	if code, err := isContextError(sourceError); err == nil {
 		return code
 	}
+	if code, err := isConnectionResetError(sourceError); err == nil {
+		return code
+	}
 
 	var apiErr *googleapi.Error
 	if !errors.As(sourceError, &apiErr) {
@@ -464,6 +467,20 @@ func isContextError(err error) (codes.Code, error) {
 	return codes.Unknown, fmt.Errorf("Not a context error: %w", err)
 }
 
+// isConnectionResetError returns the grpc error code Unavailable if the
+// passed in error contains the "connection reset by peer" string.
+func isConnectionResetError(err error) (codes.Code, error) {
+	if err == nil {
+		return codes.Unknown, fmt.Errorf("null error")
+	}
+
+	errStr := err.Error()
+	if strings.Contains(errStr, "connection reset by peer") {
+		return codes.Unavailable, nil
+	}
+	return codes.Unknown, fmt.Errorf("Not a connection reset error: %w", err)
+}
+
 // isUserMultiAttachError returns an InvalidArgument if the error is
 // multi-attach detected from the API server. If we get this error from the API
 // server, it means that the kubelet doesn't know about the multiattch so it is


Test patch:
diff --git a/pkg/common/utils_test.go b/pkg/common/utils_test.go
index 2b610e8e..0776202d 100644
--- a/pkg/common/utils_test.go
+++ b/pkg/common/utils_test.go
@@ -22,6 +22,7 @@ import (
 	"fmt"
 	"net/http"
 	"reflect"
+	"syscall"
 	"testing"
 
 	"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
@@ -1235,6 +1236,16 @@ func TestCodeForError(t *testing.T) {
 			inputErr: context.DeadlineExceeded,
 			expCode:  codes.DeadlineExceeded,
 		},
+		{
+			name:     "connection reset error",
+			inputErr: fmt.Errorf("failed to getDisk: connection reset by peer"),
+			expCode:  codes.Unavailable,
+		},
+		{
+			name:     "wrapped connection reset error",
+			inputErr: fmt.Errorf("received error: %v", syscall.ECONNRESET),
+			expCode:  codes.Unavailable,
+		},
 		{
 			name:     "status error with Aborted error code",
 			inputErr: status.Error(codes.Aborted, "aborted error"),